Full Code of canonical/microk8s for AI

master 5d5036d4fadf cached
330 files
1.5 MB
373.0k tokens
617 symbols
1 requests
Download .txt
Showing preview only (1,668K chars total). Download the full file or copy to clipboard to get everything.
Repository: canonical/microk8s
Branch: master
Commit: 5d5036d4fadf
Files: 330
Total size: 1.5 MB

Directory structure:
gitextract_osiht2xu/

├── .github/
│   ├── .jira_sync_config.yaml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── feature_request.md
│   │   └── question.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── actions/
│   │   └── test-prep/
│   │       └── action.yaml
│   ├── dependabot.yml
│   └── workflows/
│       ├── backport.yml
│       ├── build-installer.yml
│       ├── build-snap.yml
│       ├── check-formatting.yml
│       ├── check-unit-tests.yml
│       ├── cla-check.yml
│       ├── stale-cron.yaml
│       └── update-images.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build-scripts/
│   ├── .gitignore
│   ├── addons/
│   │   └── repositories.sh
│   ├── build-component.sh
│   ├── components/
│   │   ├── README.md
│   │   ├── cluster-agent/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── cni/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   └── default/
│   │   │   │       └── 0001-single-entrypoint-for-cni-tools.patch
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── containerd/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   ├── default/
│   │   │   │   │   └── 0001-microk8s-sideload-images-plugin.patch
│   │   │   │   └── v2.1.3/
│   │   │   │       └── 0001-microk8s-sideload-images-plugin.patch
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── etcd/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── flannel-cni-plugin/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── flanneld/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   └── default/
│   │   │   │       └── 0001-disable-udp-backend.patch
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── helm/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── k8s-dqlite/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── kubernetes/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   ├── v1.27.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Unix-socket-skip-validation-in-component-status.patch
│   │   │   │   ├── v1.27.4/
│   │   │   │   │   └── 0000-Kubelite-integration.patch
│   │   │   │   ├── v1.28.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   ├── v1.31.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   ├── v1.32.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   ├── v1.33.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   ├── v1.34.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   ├── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   │   └── 0002-fix-allow-node-to-get-endpointslices.patch
│   │   │   │   └── v1.35.0/
│   │   │   │       ├── 0000-Kubelite-integration.patch
│   │   │   │       ├── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │       └── 0002-fix-allow-node-to-get-endpointslices.patch
│   │   │   ├── pre-patch.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── microk8s-completion/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   └── default/
│   │   │   │       └── 0001-microk8s-autocompleter-script.patch
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── python/
│   │   │   └── requirements.txt
│   │   └── runc/
│   │       ├── build.sh
│   │       ├── patches/
│   │       │   └── default/
│   │       │       └── 0001-Disable-static-PIE-on-arm64.patch
│   │       ├── repository
│   │       ├── strict-patches/
│   │       │   ├── v1.1.12/
│   │       │   │   ├── 0001-apparmor-change-profile-immediately-not-on-exec.patch
│   │       │   │   ├── 0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch
│   │       │   │   └── 0003-standard_init_linux-change-AppArmor-profile-as-late-.patch
│   │       │   ├── v1.1.15/
│   │       │   │   ├── 0001-apparmor-change-profile-immediately-not-on-exec.patch
│   │       │   │   ├── 0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch
│   │       │   │   └── 0003-standard_init_linux-change-AppArmor-profile-as-late-.patch
│   │       │   ├── v1.2.6/
│   │       │   │   ├── 0001-apparmor-change-profile-immediately-not-on-exec.patch
│   │       │   │   ├── 0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch
│   │       │   │   └── 0003-standard_init_linux-change-AppArmor-profile-as-late-.patch
│   │       │   └── v1.3.0/
│   │       │       ├── 0001-apparmor-change-profile-immediately-not-on-exec.patch
│   │       │       ├── 0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch
│   │       │       └── 0003-standard_init_linux-change-AppArmor-profile-as-late-.patch
│   │       └── version.sh
│   ├── generate-bom.py
│   ├── images.txt
│   ├── print-patches-for.py
│   └── update-images.sh
├── docs/
│   ├── build.md
│   ├── community.md
│   └── k8s-patches.md
├── installer/
│   ├── .gitignore
│   ├── __init__.py
│   ├── build-linux.sh
│   ├── cli/
│   │   ├── __init__.py
│   │   ├── echo.py
│   │   └── microk8s.py
│   ├── common/
│   │   ├── __init__.py
│   │   ├── auxiliary.py
│   │   ├── definitions.py
│   │   ├── errors.py
│   │   └── file_utils.py
│   ├── microk8s.py
│   ├── microk8s.spec
│   ├── requirements.txt
│   ├── setup.cfg
│   ├── setup.py
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── integration/
│   │   │   └── test_cli.py
│   │   └── unit/
│   │       ├── test_auxiliary.py
│   │       └── test_cli.py
│   ├── vm_providers/
│   │   ├── __init__.py
│   │   ├── _base_provider.py
│   │   ├── _multipass/
│   │   │   ├── __init__.py
│   │   │   ├── _instance_info.py
│   │   │   ├── _multipass.py
│   │   │   ├── _multipass_command.py
│   │   │   └── _windows.py
│   │   ├── errors.py
│   │   ├── factory.py
│   │   └── repo/
│   │       ├── __init__.py
│   │       ├── errors.py
│   │       └── snaps.py
│   └── windows/
│       ├── README.md
│       └── microk8s.nsi
├── microk8s-resources/
│   ├── actions/
│   │   └── common/
│   │       └── utils.sh
│   ├── basic_auth.csv
│   ├── certs/
│   │   ├── csr-dqlite.conf.template
│   │   └── csr.conf.template
│   ├── client-x509.config.template
│   ├── client.config
│   ├── client.config.template
│   ├── containerd-profile
│   ├── default-args/
│   │   ├── admission-control-config-file.yaml
│   │   ├── apiserver-proxy
│   │   ├── certs.d/
│   │   │   ├── docker.io/
│   │   │   │   └── hosts.toml
│   │   │   └── localhost__32000/
│   │   │       └── hosts.toml
│   │   ├── cluster-agent
│   │   ├── cni-env
│   │   ├── cni-network/
│   │   │   └── flannel.conflist
│   │   ├── containerd
│   │   ├── containerd-env
│   │   ├── containerd-template.toml
│   │   ├── ctr
│   │   ├── etcd
│   │   ├── eventconfig.yaml
│   │   ├── flannel-network-mgr-config
│   │   ├── flannel-template.conflist
│   │   ├── flanneld
│   │   ├── git/
│   │   │   └── .gitconfig
│   │   ├── ha-conf
│   │   ├── k8s-dqlite
│   │   ├── k8s-dqlite-env
│   │   ├── kube-apiserver
│   │   ├── kube-controller-manager
│   │   ├── kube-proxy
│   │   ├── kube-scheduler
│   │   ├── kubectl
│   │   ├── kubectl-env
│   │   ├── kubelet
│   │   ├── kubelite
│   │   └── traefik/
│   │       ├── provider-template.yaml
│   │       └── traefik-template.yaml
│   ├── default-hooks/
│   │   ├── post-refresh.d/
│   │   │   └── 30-helm
│   │   ├── reconcile.d/
│   │   │   ├── 10-pods-restart
│   │   │   └── 90-calico-apply
│   │   └── remove.d/
│   │       ├── 10-cni-link
│   │       ├── 10-cni-link-cilium
│   │       ├── 20-cni-netns
│   │       └── 90-containers
│   ├── kubelet.config
│   ├── kubelet.config.template
│   ├── kubeproxy.config
│   ├── microk8s.default.yaml
│   └── wrappers/
│       ├── apiservice-kicker
│       ├── git.wrapper
│       ├── microk8s-add-node.wrapper
│       ├── microk8s-addons.wrapper
│       ├── microk8s-config.wrapper
│       ├── microk8s-ctr.wrapper
│       ├── microk8s-dashboard-proxy.wrapper
│       ├── microk8s-dbctl.wrapper
│       ├── microk8s-disable.wrapper
│       ├── microk8s-enable.wrapper
│       ├── microk8s-helm.wrapper
│       ├── microk8s-helm3.wrapper
│       ├── microk8s-images.wrapper
│       ├── microk8s-istioctl.wrapper
│       ├── microk8s-join.wrapper
│       ├── microk8s-kubectl.wrapper
│       ├── microk8s-leave.wrapper
│       ├── microk8s-linkerd.wrapper
│       ├── microk8s-refresh-certs.wrapper
│       ├── microk8s-remove-node.wrapper
│       ├── microk8s-reset.wrapper
│       ├── microk8s-start.wrapper
│       ├── microk8s-status.wrapper
│       ├── microk8s-stop.wrapper
│       ├── microk8s-version.wrapper
│       ├── microk8s.wrapper
│       ├── openssl.wrapper
│       ├── run-apiserver-proxy-with-args
│       ├── run-cluster-agent-with-args
│       ├── run-containerd-with-args
│       ├── run-etcd-with-args
│       ├── run-flanneld-with-args
│       ├── run-k8s-dqlite-with-args
│       └── run-kubelite-with-args
├── pyproject.toml
├── scripts/
│   ├── calico/
│   │   └── upgrade.py
│   ├── find-resolv-conf.py
│   ├── generate-cni.sh
│   ├── inspect.sh
│   ├── kill-host-pods.py
│   ├── run-lifecycle-hooks.py
│   └── wrappers/
│       ├── add_token.py
│       ├── addons.py
│       ├── common/
│       │   ├── __init__.py
│       │   ├── cluster/
│       │   │   ├── __init__.py
│       │   │   └── utils.py
│       │   └── utils.py
│       ├── dashboard_proxy.py
│       ├── dbctl.py
│       ├── disable.py
│       ├── distributed_op.py
│       ├── enable.py
│       ├── images.py
│       ├── join.py
│       ├── leave.py
│       ├── refresh_certs.py
│       ├── remove_node.py
│       ├── reset.py
│       ├── status.py
│       ├── upgrade.py
│       └── version.py
├── snap/
│   ├── hooks/
│   │   ├── configure
│   │   ├── connect-plug-network-control
│   │   ├── disconnect-plug-network-control
│   │   ├── install
│   │   ├── post-refresh
│   │   └── remove
│   └── snapcraft.yaml
├── tests/
│   ├── libs/
│   │   ├── addons-upgrade.sh
│   │   ├── addons.sh
│   │   ├── airgap.sh
│   │   ├── clustering.sh
│   │   ├── spread.sh
│   │   ├── upgrade-path.sh
│   │   └── utils.sh
│   ├── lxc/
│   │   ├── install-deps/
│   │   │   ├── images_almalinux-8
│   │   │   ├── images_archlinux
│   │   │   ├── images_centos-7
│   │   │   ├── images_centos-8-Stream
│   │   │   ├── images_debian-10
│   │   │   ├── images_debian-11
│   │   │   ├── images_debian-12
│   │   │   ├── images_fedora-37
│   │   │   ├── images_fedora-38
│   │   │   ├── images_rockylinux-8
│   │   │   ├── ubuntu_16.04
│   │   │   ├── ubuntu_18.04
│   │   │   ├── ubuntu_20.04
│   │   │   └── ubuntu_22.04
│   │   ├── microk8s-zfs.profile
│   │   └── microk8s.profile
│   ├── requirements.txt
│   ├── smoke-test.sh
│   ├── templates/
│   │   ├── bbox-local.yaml
│   │   ├── dual-stack.yaml
│   │   ├── ingress.yaml
│   │   ├── nginx-pod.yaml
│   │   ├── pvc.yaml
│   │   ├── registry-sc.yaml
│   │   └── simple-deploy.yaml
│   ├── test-cluster-agent.py
│   ├── test-cluster.py
│   ├── test-distro.sh
│   ├── test-simple.py
│   ├── test-upgrade-path.py
│   ├── test-upgrade.py
│   ├── unit/
│   │   ├── cluster/
│   │   │   ├── test_join.py
│   │   │   └── test_leave.py
│   │   ├── test_addons.py
│   │   ├── test_addtoken.py
│   │   ├── test_dashboard_proxy.py
│   │   ├── test_disable.py
│   │   ├── test_enable.py
│   │   ├── test_refresh_certs.py
│   │   ├── test_reset.py
│   │   ├── test_upgrade_calico_cni.py
│   │   ├── test_version.py
│   │   └── yamls/
│   │       ├── calico-new.yaml
│   │       ├── cni.yaml
│   │       └── invalid.yaml
│   ├── utils.py
│   ├── validators.py
│   └── verify-branches.py
├── tox.ini
└── upgrade-scripts/
    ├── 000-switch-to-calico/
    │   ├── commit-master.sh
    │   ├── commit-node.sh
    │   ├── description.txt
    │   ├── prepare-master.sh
    │   ├── prepare-node.sh
    │   ├── resources/
    │   │   └── calico.yaml
    │   ├── rollback-master.sh
    │   └── rollback-node.sh
    ├── 001-switch-to-dqlite/
    │   ├── commit-master.sh
    │   ├── commit-node.sh
    │   ├── description.txt
    │   ├── prepare-master.sh
    │   ├── prepare-node.sh
    │   ├── rollback-master.sh
    │   └── rollback-node.sh
    └── 002-switch-to-flannel-etcd/
        ├── commit-master.sh
        ├── commit-node.sh
        ├── description.txt
        ├── prepare-master.sh
        ├── prepare-node.sh
        ├── rollback-master.sh
        └── rollback-node.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/.jira_sync_config.yaml
================================================
settings:
  # Jira project key to create the issue in
  jira_project_key: "KU"

  # Dictionary mapping GitHub issue status to Jira issue status
  status_mapping:
    opened: Untriaged
    closed: done

  # (Optional) Jira project components that should be attached to the created issue
  # Component names are case-sensitive
  components:
    - Microk8s snap

  # (Optional) GitHub labels. Only issues with one of those labels will be synchronized.
  # If not specified, all issues will be synchronized
  #  labels: []

  # (Optional) (Default: false) Add a new comment in GitHub with a link to Jira created issue
  add_gh_comment: false

  # (Optional) (Default: true) Synchronize issue description from GitHub to Jira
  sync_description: true

  # (Optional) (Default: true) Synchronize comments from GitHub to Jira
  sync_comments: true

  # (Optional) (Default: None) Parent Epic key to link the issue to
  epic_key: "KU-925"

  # (Optional) Dictionary mapping GitHub issue labels to Jira issue types.
  # If label on the issue is not in specified list, this issue will be created as a Bug
  label_mapping:
    enhancement: Story


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug Report
about: Something is not working
---

<!--
   Thank you for submitting an issue. Please fill in the template below
   information about the bug you encountered.
-->

#### Summary
<!-- Please explain the bug in a few short sentences -->

#### What Should Happen Instead?
<!-- Please explain what the expected behavior is -->

#### Reproduction Steps
<!-- Are you able to consistently reproduce the issue? Please add a list of steps that lead to the bug. -->

1. ...
2. ...

#### Introspection Report
<!-- Please run `microk8s inspect` and attach the generated tarball. -->

#### Can you suggest a fix?
<!-- (This section is optional). How do you propose that the issue be fixed? -->

#### Are you interested in contributing with a fix?
<!-- yes/no, or @mention maintainers. Community contributions are welcome. -->

<!-- Thank you for making MicroK8s better -->


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature Request
about: Suggest a new feature
---

<!--
   Thank you for submitting a feature request. Please fill the template below
   with more details.
-->

#### Summary
<!-- Please explain the feature request in a few short sentences. -->

#### Why is this important?
<!-- Please explain the motivation, how it will be used, etc. -->

#### Are you interested in contributing to this feature?
<!-- yes/no, or @mention maintainers. -->


<!-- Thank you for making MicroK8s better -->


================================================
FILE: .github/ISSUE_TEMPLATE/question.yml
================================================
contact_links:
  - name: Ask a question
    url: https://kubernetes.slack.com/archives/CAUNWQ85V
    about: "For discussions and/or other questions related to MicroK8s, please use the #microk8s channel on the Kubernetes Slack"


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--
  Thank you for making MicroK8s better. Please fill the template below
  with more details.
-->

#### Summary
<!--
   Please explain the changes made in this pull request in a few short sentences.

   Link to any related issues and/or comments, e.g.

   Closes #issue-number
   References #issue-number
-->

#### Changes
<!-- Please explain the list of changes made in this PR. Mention any user-facing changes. -->

#### Testing
<!-- Please explain how you tested your changes. -->

#### Possible Regressions
<!-- (This section is optional). Could these changes introduce regressions in existing functionality? -->

#### Checklist
<!-- Please verify that you have done the following -->

* [ ] Read the [contributions](https://github.com/canonical/microk8s/blob/master/CONTRIBUTING.md) page.
* [ ] Submitted the [CLA form](https://ubuntu.com/legal/contributors/agreement), if you are a first time contributor.
* [ ] The introduced changes are covered by unit and/or integration tests.

#### Notes
<!-- Please add any other information that you think may be relevant -->


================================================
FILE: .github/actions/test-prep/action.yaml
================================================
name: Prepare test prerequisites

runs:
  using: "composite"
  steps:
    - name: Setup Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"
    - name: Install test dependencies
      shell: bash
      run: |
        set -x
        sudo pip3 install -r ./tests/requirements.txt
    # Docker sets iptables rules that interfere with LXD and K8s.
    # https://documentation.ubuntu.com/lxd/en/latest/howto/network_bridge_firewalld/#prevent-connectivity-issues-with-lxd-and-docker
    - name: Apply Docker iptables workaround
      shell: bash
      run: sudo iptables -I DOCKER-USER -j ACCEPT
    - name: Fetch snap
      uses: actions/download-artifact@v4
      with:
        name: microk8s.snap
        path: build


================================================
FILE: .github/dependabot.yml
================================================
# Set update schedule for GitHub Actions

version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      # Check for updates to GitHub Actions every weekday
      interval: "daily"


================================================
FILE: .github/workflows/backport.yml
================================================
name: Backport merged pull request
on:
  pull_request_target:
    types: [closed]
  issue_comment:
    types: [created]
permissions:
  contents: write # so it can comment
  pull-requests: write # so it can create pull requests
jobs:
  backport:
    name: Backport pull request
    runs-on: ubuntu-latest

    # Only run when pull request is merged
    # or when a comment containing `/backport` is created by someone other than the
    # https://github.com/backport-action bot user (user id: 97796249). Note that if you use your
    # own PAT as `github_token`, that you should replace this id with yours.
    # cdkbot's user ID is 99445902.
    if: >
      (
        github.event_name == 'pull_request_target' &&
        github.event.pull_request.merged
      ) || (
        github.event_name == 'issue_comment' &&
        github.event.issue.pull_request &&
        github.event.comment.user.id != 99445902 &&
        contains(github.event.comment.body, '/backport')
      )
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Create backport pull requests
        uses: korthout/backport-action@v3
        with:
          # Set (default) action parameters explicitly.
          branch_name: backport-${pull_number}-to-${target_branch}
          cherry_picking: auto
          copy_assignees: false
          copy_milestone: false
          copy_requested_reviewers: false
          experimental: >
            {
              "conflict_resolution": "fail"
            }
          github_token: ${{ secrets.BOT_TOKEN }}
          github_workspace: ${{ github.workspace }}
          label_pattern: ^backport ([^ ]+)$
          merge_commits: fail
          pull_description: |-
            # Description
            Backport of #${pull_number} to `${target_branch}`.
          pull_title: >-
            [Backport ${target_branch}] ${pull_title}


================================================
FILE: .github/workflows/build-installer.yml
================================================
name: Build MicroK8s Installers

on:
  push:
    branches:
      - "**install**"
  pull_request:
    branches:
      - "**install**"

jobs:
  windows:
    runs-on: windows-latest
    defaults:
      run:
        working-directory: ${{ github.workspace }}/installer/windows
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Set up Python 3.8
        uses: actions/setup-python@v5.5.0
        with:
          python-version: 3.8
      - name: Install Python requirements
        run: python -m pip install -r ../requirements.txt
      - name: Build exe
        working-directory: ${{ github.workspace }}/installer
        run: pyinstaller.exe ./microk8s.spec
      - name: Move exe to installer build directory
        working-directory: ${{ github.workspace }}/installer
        run: move microk8s.exe ./windows/microk8s.exe
      - name: Download EnVar plugin for NSIS
        uses: carlosperate/download-file-action@v2.0.2
        with:
          file-url: https://github.com/GsNSIS/EnVar/releases/download/v0.3.1/EnVar-Plugin.zip
          file-name: envar_plugin.zip
          location: ${{ github.workspace }}
      - name: Extract EnVar plugin
        run: 7z x -o"C:/Program Files (x86)/NSIS" "${{ github.workspace }}/envar_plugin.zip"
      - name: Download Multipass installer
        uses: carlosperate/download-file-action@v2.0.2
        with:
          file-url: https://github.com/canonical/multipass/releases/download/v1.12.2/multipass-1.12.2+win-win64.exe
          file-name: multipass.exe
          location: ${{ github.workspace }}/installer/windows
      - name: Download kubectl
        uses: carlosperate/download-file-action@v2.0.2
        with:
          file-url: https://storage.googleapis.com/kubernetes-release/release/v1.28.3/bin/windows/amd64/kubectl.exe
          file-name: kubectl.exe
          location: ${{ github.workspace }}/installer/windows
      - name: Create installer
        run: makensis.exe ${{ github.workspace }}/installer/windows/microk8s.nsi
      - name: Upload installer
        uses: actions/upload-artifact@v4
        with:
          name: Windows installer
          path: ${{ github.workspace }}/installer/windows/microk8s-installer.exe


================================================
FILE: .github/workflows/build-snap.yml
================================================
name: Build and test MicroK8s snap

on:
  pull_request:
    branches:
      - master

jobs:
  build:
    name: Create snap package
    runs-on: ubuntu-latest

    steps:
      - name: Checking out repo
        uses: actions/checkout@v4
      - name: Install lxd
        run: |
          sudo lxd init --auto
          sudo usermod --append --groups lxd $USER
          # `newgrp` does not work in GitHub Actions; use `sudo --user` instead
          # See https://github.com/actions/runner-images/issues/9932#issuecomment-2573170305
          sudo --user "$USER" --preserve-env --preserve-env=PATH -- env -- lxc version
      # Docker sets iptables rules that interfere with LXD or K8s.
      # https://documentation.ubuntu.com/lxd/en/latest/howto/network_bridge_firewalld/#prevent-connectivity-issues-with-lxd-and-docker
      - name: Apply Docker iptables workaround
        shell: bash
        run: sudo iptables -I DOCKER-USER -j ACCEPT
      - name: Install snapcraft
        run: |
          sudo snap install snapcraft --classic
      - name: Install snapd from candidate
        run: |
          # TODO(neoaggelos): revert this after latest/beta is working again
          sudo snap refresh snapd --channel=latest/stable
      - name: Build snap
        run: |
          sudo --user "$USER" --preserve-env --preserve-env=PATH -- env -- snapcraft --use-lxd
          sudo mv microk8s*.snap microk8s.snap
      - name: Uploading snap
        uses: actions/upload-artifact@v4
        with:
          name: microk8s.snap
          path: microk8s.snap

  test-upgrade:
    name: Upgrade path test
    runs-on: ubuntu-latest
    needs: build
    timeout-minutes: 30
    steps:
      - name: Checking out repo
        uses: actions/checkout@v4
      - name: Prepare test prerequisites
        uses: ./.github/actions/test-prep
      - name: Running upgrade path test
        run: |
          sudo -E UPGRADE_MICROK8S_FROM=latest/edge UPGRADE_MICROK8S_TO=$PWD/build/microk8s.snap pytest -s ./tests/test-upgrade-path.py

  test-addons-core:
    name: Test core addons
    runs-on: ubuntu-latest
    needs: build
    timeout-minutes: 60
    env:
      # Avoid truncated "ps" output
      COLUMNS: 2048
    steps:
      - name: Checking out repo
        uses: actions/checkout@v4
      - name: Prepare test prerequisites
        uses: ./.github/actions/test-prep
      - name: Running addons tests
        env:
          UNDER_TIME_PRESSURE: ${{ !contains(github.event.pull_request.labels.*.name, 'run-all-tests') }}
        run: |
          set -x
          sudo snap install build/microk8s.snap --classic --dangerous
          ./tests/smoke-test.sh
          # The GitHub runner is using the 10.1.0.0/16 CIDR, which would conflict with
          # kube-ovn's default POD_CIDR. They have to be different.
          export POD_CIDR="10.200.0.0/16"
          export POD_GATEWAY="10.200.0.1"
          export SKIP_PROMETHEUS="False"
          export UNDER_TIME_PRESSURE=${UNDER_TIME_PRESSURE@u}
          sudo -E bash -c "cd /var/snap/microk8s/common/addons/core/tests; pytest -s -ra test-addons.py"

  test-addons-community:
    name: Test community addons
    runs-on: ubuntu-latest
    needs: build
    timeout-minutes: 60
    steps:
      - name: Checking out repo
        uses: actions/checkout@v4
      - name: Prepare test prerequisites
        uses: ./.github/actions/test-prep
      - name: Running addons tests
        env:
          UNDER_TIME_PRESSURE: ${{ !contains(github.event.pull_request.labels.*.name, 'run-all-tests') }}
        run: |
          set -x
          sudo snap install build/microk8s.snap --classic --dangerous
          sudo microk8s enable community
          export UNDER_TIME_PRESSURE=${UNDER_TIME_PRESSURE@u}
          sudo -E bash -c "cd /var/snap/microk8s/common/addons/community/; pytest -s -ra ./tests/"

  test-addons-core-upgrade:
    name: Test core addons upgrade
    runs-on: ubuntu-latest
    needs: build
    timeout-minutes: 30
    steps:
      - name: Checking out repo
        uses: actions/checkout@v4
      - name: Prepare test prerequisites
        uses: ./.github/actions/test-prep
      - name: Running upgrade tests
        env:
          UNDER_TIME_PRESSURE: ${{ !contains(github.event.pull_request.labels.*.name, 'run-all-tests') }}
        run: |
          set -x
          export UNDER_TIME_PRESSURE=${UNDER_TIME_PRESSURE@u}
          sudo -E bash -c "UPGRADE_MICROK8S_FROM=latest/edge UPGRADE_MICROK8S_TO=$PWD/build/microk8s.snap pytest -s ./tests/test-upgrade.py"

  test-cluster-agent:
    name: Cluster agent health check
    runs-on: ubuntu-latest
    needs: build
    timeout-minutes: 30
    steps:
      - name: Checking out repo
        uses: actions/checkout@v4
      - name: Prepare test prerequisites
        uses: ./.github/actions/test-prep
      - name: Running cluster agent health check
        run: |
          set -x
          sudo snap install build/microk8s.snap --classic --dangerous
          sudo -E bash -c "pytest -s ./tests/test-cluster-agent.py"

  test-airgap:
    name: Test airgap installation
    runs-on: ubuntu-latest
    needs: build
    timeout-minutes: 30
    steps:
      - name: Checking out repo
        uses: actions/checkout@v4
      - name: Prepare test prerequisites
        uses: ./.github/actions/test-prep
      - name: Initialize LXD
        run: |
          sudo lxd init --auto
          sudo lxc network set lxdbr0 ipv6.address=none
          sudo usermod --append --groups lxd $USER
          # `newgrp` does not work in GitHub Actions; use `sudo --user` instead
          # See https://github.com/actions/runner-images/issues/9932#issuecomment-2573170305
          sudo --user "$USER" --preserve-env --preserve-env=PATH -- env -- lxc version
      - name: Run airgap tests
        run: |
          sudo -E bash -x -c "./tests/libs/airgap.sh --distro ubuntu:22.04 --channel $PWD/build/microk8s.snap"

  security-scan:
    name: Security scan
    outputs:
      sarif_files: ${{ steps.get_sarif_files.outputs.sarif-files }}
    runs-on: ubuntu-latest
    needs: build
    timeout-minutes: 30
    steps:
      - name: Checking out repo
        uses: actions/checkout@v4
      - name: Fetch snap
        uses: actions/download-artifact@v4
        with:
          name: microk8s.snap
          path: build
      - name: Create sarifs directory
        run: |
          mkdir -p sarifs
      - name: Install Trivy vulnerability scanner
        uses: aquasecurity/setup-trivy@v0.2.2
      - name: Run Trivy vulnerability scanner on codebase
        run: |
          trivy fs . --format sarif --severity CRITICAL > sarifs/trivy-microk8s-repo-scan--results.sarif
      - name: Run Trivy vulnerability scanner on images
        run: |
          for i in $(cat ./build-scripts/images.txt) ; do
            name=$(echo  $i | awk -F ':|/' '{print $(NF-1)}')
            trivy image $i --format sarif > sarifs/$name.sarif
          done
      - name: Run Trivy vulnerability scanner on the snap
        run: |
          cp build/microk8s.snap .
          unsquashfs microk8s.snap
          trivy rootfs ./squashfs-root/ --format sarif > sarifs/snap.sarif
      - name: Generate list of SARIF files
        id: get_sarif_files
        run: |
          sarif_files=$(find sarifs -name "*.sarif" -printf "%P\n" | jq -R -s -c 'split("\n") | map(select(length > 0))')
          echo "sarif-files=$sarif_files" >> "$GITHUB_OUTPUT"
      - name: Upload SARIF files artifact
        uses: actions/upload-artifact@v4
        with:
          name: sarifs
          path: sarifs
          retention-days: 1

  upload_sarifs_matrix:
    needs: security-scan
    runs-on: ubuntu-latest
    strategy:
      fail-fast: true
      matrix:
        sarif_file_path: ${{ fromJson(needs.security-scan.outputs.sarif_files) }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Download SARIF files artifact
        uses: actions/download-artifact@v4
        with:
          name: sarifs
          path: sarifs
      - name: Prepare SARIF category
        id: prepare_category
        run: |
          sarif_file="${{ matrix.sarif_file_path }}"
          base_name=$(basename "$sarif_file" .sarif)
          echo "category=$base_name" >> "$GITHUB_OUTPUT"
      - name: Upload SARIF file
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: sarifs/${{ matrix.sarif_file_path }}
          category: ${{ steps.prepare_category.outputs.category }}


================================================
FILE: .github/workflows/check-formatting.yml
================================================
name: Lint Code

on:
  - pull_request

jobs:
  check-formatting:
    name: Check Formatting
    runs-on: ubuntu-latest

    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install tox --fix-missing
          sudo snap install node --classic
          sudo npm install --save-dev --save-exact -g prettier
      - name: Check Python formatting
        run: |
          tox -e lint
      - name: Check YAML formatting
        run: |
          set -eux
          prettier --check $(find . -name "*.yaml" -o -name "*.yml" | \
            grep -v "./microk8s-resources/actions/ingress.yaml" | \
            grep -v "./microk8s-resources/actions/metallb.yaml" | \
            grep -v invalid.yaml | \
            grep -v calico)


================================================
FILE: .github/workflows/check-unit-tests.yml
================================================
name: Unit Tests

on:
  - pull_request

jobs:
  check-unit-tests:
    name: Check Unit Tests
    runs-on: ubuntu-latest

    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install tox --fix-missing
          sudo pip3 install -U pytest==7.1.3 sh==1.14.3
      - name: Check Units
        run: |
          tox -e scripts
          tox -e wrappers
          tox -e cluster
      - name: Verify branches
        run: |
          pytest -s ./tests/verify-branches.py


================================================
FILE: .github/workflows/cla-check.yml
================================================
name: cla-check

on:
  pull_request:
    branches: [master, default]

jobs:
  cla-check:
    runs-on: ubuntu-latest
    steps:
      - name: Check if CLA signed
        uses: canonical/has-signed-canonical-cla@v2


================================================
FILE: .github/workflows/stale-cron.yaml
================================================
name: Close inactive issues or PRs
on:
  schedule:
    - cron: "0 0 * * *" # Runs every midnight
  pull_request:
    paths:
      - .github/workflows/stale-cron.yaml

jobs:
  close-issues:
    runs-on: ubuntu-latest
    permissions:
      issues: write
      pull-requests: write
    steps:
      - uses: actions/stale@v9
        with:
          days-before-stale: 330
          days-before-close: 30
          stale-issue-label: inactive
          stale-issue-message: >
            This issue has been automatically marked as stale because it has
            not had recent activity. It will be closed if no further activity
            occurs. Thank you for your contributions.
          close-issue-message: >
            This issue was closed because it has been inactive for 30 days
            since being marked as stale.
          exempt-pr-labels: pinned,security
          exempt-issue-labels: pinned,security
          repo-token: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/update-images.yml
================================================
name: Update list of images

on:
  workflow_dispatch:
  schedule:
    - cron: "0 10 * * *"

permissions:
  contents: write
  pull-requests: write

jobs:
  update:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          # Latest branches
          - { branch: master, channel: latest/edge }
          # Stable branches
          - { branch: "1.32", channel: "1.32" }
          - { branch: "1.31", channel: "1.31" }
          - { branch: "1.30", channel: "1.30" }
          - { branch: "1.29", channel: "1.29" }
          - { branch: "1.28", channel: "1.28" }
          - { branch: "1.27", channel: "1.27" }
          # Stable strict branches
          - { branch: 1.32-strict, channel: 1.32-strict }
          - { branch: 1.31-strict, channel: 1.31-strict }
          - { branch: 1.30-strict, channel: 1.30-strict }
          - { branch: 1.29-strict, channel: 1.29-strict }
          - { branch: 1.28-strict, channel: 1.28-strict }
          - { branch: 1.27-strict, channel: 1.27-strict }
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ matrix.branch }}
      - name: Update image list
        run: |
          ./build-scripts/update-images.sh ${{ matrix.channel }} build-scripts/images.txt
      - name: Create pull request
        uses: peter-evans/create-pull-request@v7
        with:
          commit-message: update list of images used by ${{ matrix.channel }}
          title: "[${{ matrix.channel }}] Update MicroK8s images"
          body: update list of images used by ${{ matrix.channel }}
          reviewers: berkayoz,ktsakalozos
          branch: auto-update-images/${{ matrix.branch }}
          delete-branch: true
          base: ${{ matrix.branch }}


================================================
FILE: .gitignore
================================================
/build/
/parts/
/prime/
/stage/
!/snap/hooks/
*.snap
microk8s.egg-info/
microk8s_source.tar.bz2
tests/__pycache__
.idea/
**/tests/*.pyc
.venv/
.vscode/
/installer/.venv/
/installer/**/__pycache__
/installer/dist/
/installer/build/
.tox/
.tox_env/
__pycache__/
microk8s_*.txt #Remote build log


================================================
FILE: CODE_OF_CONDUCT.md
================================================
MicroK8s has adopted the [Ubuntu Code of Conduct v2.0](https://ubuntu.com/community/ethos/code-of-conduct)


================================================
FILE: CONTRIBUTING.md
================================================
# Contributor Guide

MicroK8s is open source ([Apache License 2.0](./LICENSE)) and actively seeks any community contributions for code, add-ons, suggestions and documentation.
Many of the features currently part of MicroK8s originated in the community, and we are very keen for that to continue. This page details a few notes, 
workflows and suggestions for how to make contributions most effective and help us all build a better MicroK8s for everyone - please give them a read before
working on any contributions.

## Licensing

MicroK8s has been created under the [Apache License 2.0](./LICENSE), which will cover any contributions you may make to this project. Please familiarise
yourself with the terms of the license.

Additionally, MicroK8s uses the Harmony CLA agreement.  It’s the easiest way for you to give us permission to use your contributions. 
In effect, you’re giving us a licence, but you still own the copyright — so you retain the right to modify your code and use it in
other projects. Please [sign the CLA here](https://ubuntu.com/legal/contributors/agreement) before making any contributions.

## Code of conduct

MicroK8s has adopted the Ubuntu code of Conduct. You can read this in full [here](https://ubuntu.com/community/code-of-conduct).

## Contributing code

The workflow for contributing code is as follows:

1. **Create/choose an issue**: MicroK8s tracks issues at [https://github.com/canonical/microk8s/issues](https://github.com/canonical/microk8s/issues). If you
   want to work on a new feature, create an issue first! This gives everyone a place to discuss scope and implementation.
2. **Create a fork of the MicroK8s repo**
3. **Make a new branch for your contribution**. Write your code there.
4. For details on how to **build and test MicroK8s**, see the [build instructions](./docs/build.md). Add new tests as needed,
   and make sure the existing tests continue to pass when your changes are complete.
5. **Submit a pull request** to get changes from your branch into master. You can add "#Fixes xxx" where `xxx` is the issue number to 
   automatically link to the issue you chose or created earlier.
6. Someone will review your PR and may make suggestions or have comments, so **keep an eye on the PR status** in case there are changes to make
7. **Please make sure you have submitted your [CLA form](https://ubuntu.com/legal/contributors/agreement) if you are a first time contributor**.
8. Thanks!

## Documentation

Docs for MicroK8s are published online at [https://microk8s.io/docs](https://microk8s.io/docs). You can make suggestions and edit the pages themselves by joining 
the Kubernetes discourse at [discuss.kubernetes.io](https://discuss.kubernetes.io/t/introduction-to-microk8s/11243) or follow the link at
the bottom of any of the pages published at [https://microk8s.io/docs](https://microk8s.io/docs)
There is a documentation page which describes how to write and edit docs, [published as part of the documentation](https://microk8s.io/docs/docs).



================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2018 Canonical, Ltd.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
<img src="docs/images/MicroK8s-logo-RGB-2022.png" width="400px;" />

[![](https://github.com/canonical/microk8s/actions/workflows/build-snap.yml/badge.svg)](https://github.com/canonical/microk8s/actions/workflows/build-snap.yml)
[![](https://snapcraft.io/microk8s/badge.svg)](https://snapcraft.io/microk8s)

<img src="/docs/images/certified_kubernetes_color-222x300.png" align="right" width="200px">

## The smallest, fastest Kubernetes

Single-package fully conformant lightweight Kubernetes that works on [42
flavours of Linux](https://snapcraft.io/microk8s). Perfect for:

- Developer workstations
- IoT
- Edge
- CI/CD

 > Canonical might have assembled the easiest way to provision a single node Kubernetes cluster - [Kelsey Hightower](https://twitter.com/kelseyhightower/status/1120834594138406912)

## Why MicroK8s?

- **Small**. Developers want the smallest K8s for laptop and workstation
  development.  MicroK8s provides a standalone K8s compatible with Azure
  AKS, Amazon EKS, Google GKE when you run it on Ubuntu.

- **Simple**. Minimize administration and operations with a single-package
  install that has no moving parts for simplicity and certainty. All
  dependencies and batteries included.

- **Secure**. Updates are available for all security issues and can be
  applied immediately or scheduled to suit your maintenance cycle.

- **Current**. MicroK8s tracks upstream and releases beta, RC and final bits
  the same day as upstream K8s. You can track latest K8s or stick to any
  release version from 1.10 onwards.

- **Comprehensive**. MicroK8s includes a curated collection of manifests for
  common K8s capabilities and services:

  - Service Mesh: Istio, Linkerd
  - Serverless: Knative
  - Monitoring: Fluentd, Prometheus, Grafana, Metrics
  - Ingress, DNS, Dashboard, Clustering
  - Automatic updates to the latest Kubernetes version
  - GPGPU bindings for AI/ML

Drop us a line at [MicroK8s in the Wild](docs/community.md) if you are
doing something fun with MicroK8s!

## Quickstart

Install MicroK8s with:

```
snap install microk8s --classic
```

MicroK8s includes a `microk8s kubectl` command:

```
sudo microk8s kubectl get nodes
sudo microk8s kubectl get services
```

To use MicroK8s with your existing kubectl:

```
sudo microk8s kubectl config view --raw > $HOME/.kube/config
```

#### User access without sudo
The *microk8s* user group is created during the snap installation. Users in that group
are granted access to `microk8s` commands. To add a user to that group:
```
sudo usermod -a -G microk8s <username>
```


#### Kubernetes add-ons

MicroK8s installs a barebones upstream Kubernetes. Additional services like dns and the Kubernetes dashboard can be enabled using the `microk8s enable` command.

```
sudo microk8s enable dns
sudo microk8s enable dashboard
```

Use `microk8s status` to see a list of enabled and available addons. You can find the addon manifests and/or scripts under `${SNAP}/actions/`, with `${SNAP}` pointing by default to `/snap/microk8s/current`.

## Documentation

The [official docs](https://microk8s.io/docs/) are maintained in the
Kubernetes upstream Discourse.

Take a look at the [build instructions](docs/build.md) if you want to
contribute to MicroK8s.

<a href="https://snapcraft.io/microk8s" title="Get it from the Snap Store">
            <img src="https://snapcraft.io/static/images/badges/en/snap-store-white.svg" alt="Get it from the Snap Store" width="200" />
          </a>

<a href="https://github.com/canonical/microk8s/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=canonical/microk8s" />
</a>


================================================
FILE: build-scripts/.gitignore
================================================
.build
.install


================================================
FILE: build-scripts/addons/repositories.sh
================================================
#!/bin/bash -x

# List of addon repositories to bundle in the snap
# (name),(repository),(reference)
ADDONS_REPOS="
core,https://github.com/canonical/microk8s-core-addons,main
community,https://github.com/canonical/microk8s-community-addons,main
"

# List of addon repositories to automatically enable
ADDONS_REPOS_ENABLED="core"

INSTALL="${1}"
if [ -d "${INSTALL}/addons" ]; then
  rm -rf "${INSTALL}/addons"
fi
if [ -d addons ]; then
  rm -rf addons
fi

IFS=';'
echo "${ADDONS_REPOS}" | while read line; do
  if [ -z "${line}" ];
    then continue
  fi
  name="$(echo ${line} | cut -f1 -d',')"
  repository="$(echo ${line} | cut -f2 -d',')"
  reference="$(echo ${line} | cut -f3 -d',')"
  git clone "${repository}" -b "${reference}" "addons/${name}"
done
echo "${ADDONS_REPOS_ENABLED}" > addons/.auto-add

cp -r "addons" "${INSTALL}/addons"


================================================
FILE: build-scripts/build-component.sh
================================================
#!/bin/bash

set -ex

DIR=`realpath $(dirname "${0}")`

BUILD_DIRECTORY="${SNAPCRAFT_PART_BUILD:-${DIR}/.build}"
INSTALL_DIRECTORY="${SNAPCRAFT_PART_INSTALL:-${DIR}/.install}"

mkdir -p "${BUILD_DIRECTORY}" "${INSTALL_DIRECTORY}"

COMPONENT_NAME="${1}"
COMPONENT_DIRECTORY="${DIR}/components/${COMPONENT_NAME}"

GIT_REPOSITORY="$(cat "${COMPONENT_DIRECTORY}/repository")"
GIT_TAG="$("${COMPONENT_DIRECTORY}/version.sh")"

COMPONENT_BUILD_DIRECTORY="${BUILD_DIRECTORY}/${COMPONENT_NAME}"

# cleanup git repository if we cannot git checkout to the build tag
if [ -d "${COMPONENT_BUILD_DIRECTORY}" ]; then
  cd "${COMPONENT_BUILD_DIRECTORY}"
  if ! git checkout "${GIT_TAG}"; then
    cd "${BUILD_DIRECTORY}"
    rm -rf "${COMPONENT_BUILD_DIRECTORY}"
  fi
fi

if [ ! -d "${COMPONENT_BUILD_DIRECTORY}" ]; then
  git clone "${GIT_REPOSITORY}" --depth 1 -b "${GIT_TAG}" "${COMPONENT_BUILD_DIRECTORY}"
fi

cd "${COMPONENT_BUILD_DIRECTORY}"
git config user.name "MicroK8s builder bot"
git config user.email "microk8s-builder-bot@canonical.com"

if [ -e "${COMPONENT_DIRECTORY}/pre-patch.sh" ]; then
  bash -xe "${COMPONENT_DIRECTORY}/pre-patch.sh"
fi

for patch in $(python3 "${DIR}/print-patches-for.py" "${COMPONENT_NAME}" "${GIT_TAG}"); do
  git am "${patch}"
done

bash -xe "${COMPONENT_DIRECTORY}/build.sh" "${INSTALL_DIRECTORY}" "${GIT_TAG}"


================================================
FILE: build-scripts/components/README.md
================================================
# Parts directory

This directory contains the build scripts for Go components built into MicroK8s.

The directory structure looks like this:

```
build-scripts/
    build-component.sh              <-- runs as `build-component.sh $component_name`
                                        - checks out the git repository
                                        - runs the `pre-patch.sh` script (if any)
                                        - applies the patches (if any)
                                        - runs the `build.sh` script to build the component
    component/
        $component_name/
            repository              <-- git repository to clone
            version.sh              <-- prints the repository tag or commit to checkout
            build.sh                <-- runs as `build.sh $output $version`
                                        first argument is the output directory where
                                        binaries should be placed, second is the component version
            pre-patch.sh            <-- runs as `pre-patch.sh`. takes any action needed before applying
                                        the component patches
            patches/                <-- list of patches to apply after checkout (see section below)
                ...
            strict-patches/         <-- list of extra patches to apply when building strictly confined snap
                ...
```

## Applying patches

Most MicroK8s components are retrieved from an upstream source (specified in the `repository`), with a specific tag (specified in `version.sh`), have some patches applied to them (from the `patches/` and `strict-patches/` directories) and are then built (using `build.sh`).


This section explains the directory format for the `patches` and `strict-patches` directories. The same rules apply for both. Note that the `strict-patches` (if any) are applied **after** any `patches` have been applied.

Our patches do not frequently change between versions, but they do have to be rebased from time to time, which breaks compatibility with older versions. For that reason, we maintain a set of patches for each version that introduces a breaking change. Consider the following directory structure for the Kubernetes component.

```
patches/default/0.patch
patches/v1.27.0/a.patch
patches/v1.27.0/b.patch
patches/v1.27.4/c.patch
patches/v1.28.0/d.patch
patches/v1.28.0-beta.0/e.patch
```

The Kubernetes version to build may be decided dynamically while building the snap, or be pinned to a specified version. The following table shows which patches we would apply depending on the Kubernetes version that we build:

| Kubernetes version | Applied patches         | Explanation                                                                                |
| ------------------ | ----------------------- | ------------------------------------------------------------------------------------------ |
| `v1.27.0`          | `a.patch` and `b.patch` |                                                                                            |
| `v1.27.1`          | `a.patch` and `b.patch` | In case there is no exact match, find the most recent older version                        |
| `v1.27.4`          | `c.patch`               | Older patches are not applied                                                              |
| `v1.27.12`         | `c.patch`               | In semver, `v1.27.12 > v1.27.4` so we again must get the most recent patches               |
| `v1.28.0-rc.0`     | `d.patch`               | Extra items from semver are ignored, so we can define the `v1.28.0` patch and be done      |
| `v1.28.0-beta.0`   | `e.patch`               | Extra items from semver are ignored, but due to exact match this patch is used instead     |
| `v1.28.0`          | `d.patch`               | Extra items from semver are ignored, so we can define the `v1.28.0` patch and be done      |
| `v1.28.4`          | `d.patch`               | Picks the patches from the stable versions only, not from beta                             |
| `v1.29.1`          | `d.patch`               | Uses patches from most recent version, even if on a different minor                        |
| `hack/branch`      | `0.patch`               | If not semver and no match, any patches from the `default/` directory are applied (if any) |

Same logic applies for all other components as well.

### Testing which patches would be applied

You can verify which set of patches would be applied in any case using the `print-patches-for.py` script directly:

```bash
$ ./build-scripts/print-patches-for.py kubernetes v1.27.4
/home/ubuntu/microk8s/build-scripts/components/kubernetes/patches/v1.27.4/0000-Kubelite-integration.patch
$ ./build-scripts/print-patches-for.py kubernetes v1.27.3
/home/ubuntu/microk8s/build-scripts/components/kubernetes/patches/v1.27.0/0000-Kubelite-integration.patch
/home/ubuntu/microk8s/build-scripts/components/kubernetes/patches/v1.27.0/0001-Unix-socket-skip-validation-in-component-status.patch
$ ./build-scripts/print-patches-for.py kubernetes v1.28.1
/home/ubuntu/microk8s/build-scripts/components/kubernetes/patches/v1.28.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch
/home/ubuntu/microk8s/build-scripts/components/kubernetes/patches/v1.28.0/0000-Kubelite-integration.patch
```

### How to add support for newer versions

When a new release comes out which is no longer compatible with the existing latest patches, simply create a new directory under `patches/` with the new version number. This ensures that previous versions will still work, and newer ones will pick up the fixed patches.


================================================
FILE: build-scripts/components/cluster-agent/build.sh
================================================
#!/bin/bash

export INSTALL="${1}/bin"
mkdir -p "${INSTALL}"

make cluster-agent
cp cluster-agent "${INSTALL}"


================================================
FILE: build-scripts/components/cluster-agent/repository
================================================
https://github.com/canonical/microk8s-cluster-agent


================================================
FILE: build-scripts/components/cluster-agent/version.sh
================================================
#!/bin/bash

echo "main"


================================================
FILE: build-scripts/components/cni/build.sh
================================================
#!/bin/bash

VERSION="${2}"

INSTALL="${1}/opt/cni/bin"
mkdir -p "${INSTALL}"

# these would very tedious to apply with a patch
go get github.com/docker/docker/pkg/reexec
go mod vendor
sed -i 's/^package main/package plugin_main/' plugins/*/*/*.go
sed -i 's/^func main()/func Main()/' plugins/*/*/*.go

export CGO_ENABLED=0

go build -o cni -ldflags "-s -w -extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=${VERSION}" ./cni.go

cp cni "${INSTALL}/"
for plugin in dhcp host-local static bridge host-device ipvlan loopback macvlan ptp vlan bandwidth firewall portmap sbr tuning vrf; do
  ln -f -s ./cni "${INSTALL}/${plugin}"
done


================================================
FILE: build-scripts/components/cni/patches/default/0001-single-entrypoint-for-cni-tools.patch
================================================
From 3d0636d0ad86c9050da190b50bc01387d71dc80a Mon Sep 17 00:00:00 2001
From: MicroK8s builder bot <microk8s-builder-bot@canonical.com>
Date: Sun, 12 Feb 2023 13:34:45 +0000
Subject: [PATCH] single entrypoint for cni tools

---
 cni.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 cni.go

diff --git a/cni.go b/cni.go
new file mode 100644
index 0000000..93828f9
--- /dev/null
+++ b/cni.go
@@ -0,0 +1,54 @@
+package main
+
+import (
+	"os"
+	"path/filepath"
+
+	"github.com/docker/docker/pkg/reexec"
+
+	ipam_dhcp "github.com/containernetworking/plugins/plugins/ipam/dhcp"
+	ipam_host_local "github.com/containernetworking/plugins/plugins/ipam/host-local"
+	ipam_static "github.com/containernetworking/plugins/plugins/ipam/static"
+
+	main_bridge "github.com/containernetworking/plugins/plugins/main/bridge"
+	main_host_device "github.com/containernetworking/plugins/plugins/main/host-device"
+	main_ipvlan "github.com/containernetworking/plugins/plugins/main/ipvlan"
+	main_loopback "github.com/containernetworking/plugins/plugins/main/loopback"
+	main_macvlan "github.com/containernetworking/plugins/plugins/main/macvlan"
+	main_ptp "github.com/containernetworking/plugins/plugins/main/ptp"
+	main_vlan "github.com/containernetworking/plugins/plugins/main/vlan"
+
+	meta_bandwidth "github.com/containernetworking/plugins/plugins/meta/bandwidth"
+	meta_firewall "github.com/containernetworking/plugins/plugins/meta/firewall"
+	meta_portmap "github.com/containernetworking/plugins/plugins/meta/portmap"
+	meta_sbr "github.com/containernetworking/plugins/plugins/meta/sbr"
+	meta_tuning "github.com/containernetworking/plugins/plugins/meta/tuning"
+	meta_vrf "github.com/containernetworking/plugins/plugins/meta/vrf"
+)
+
+func main() {
+	os.Args[0] = filepath.Base(os.Args[0])
+	if reexec.Init() {
+		return
+	}
+	panic("invalid entrypoint name")
+}
+
+func init() {
+	reexec.Register("dhcp", ipam_dhcp.Main)
+	reexec.Register("host-local", ipam_host_local.Main)
+	reexec.Register("static", ipam_static.Main)
+	reexec.Register("bridge", main_bridge.Main)
+	reexec.Register("host-device", main_host_device.Main)
+	reexec.Register("ipvlan", main_ipvlan.Main)
+	reexec.Register("loopback", main_loopback.Main)
+	reexec.Register("macvlan", main_macvlan.Main)
+	reexec.Register("ptp", main_ptp.Main)
+	reexec.Register("vlan", main_vlan.Main)
+	reexec.Register("bandwidth", meta_bandwidth.Main)
+	reexec.Register("firewall", meta_firewall.Main)
+	reexec.Register("portmap", meta_portmap.Main)
+	reexec.Register("sbr", meta_sbr.Main)
+	reexec.Register("tuning", meta_tuning.Main)
+	reexec.Register("vrf", meta_vrf.Main)
+}
-- 
2.25.1


================================================
FILE: build-scripts/components/cni/repository
================================================
https://github.com/containernetworking/plugins


================================================
FILE: build-scripts/components/cni/version.sh
================================================
#!/bin/bash

# Match https://github.com/kubernetes/kubernetes/blob/master/build/dependencies.yaml#L20
echo "v1.8.0"


================================================
FILE: build-scripts/components/containerd/build.sh
================================================
#!/bin/bash

INSTALL="${1}/bin"
mkdir -p "${INSTALL}"

VERSION="${2}"
REVISION=$(git rev-parse HEAD)

sed -i "s,^VERSION.*$,VERSION=${VERSION}," Makefile
sed -i "s,^REVISION.*$,REVISION=${REVISION}," Makefile

export STATIC=1
for bin in ctr containerd containerd-shim-runc-v2; do
  make "bin/${bin}"
  cp "bin/${bin}" "${INSTALL}/${bin}"
done


================================================
FILE: build-scripts/components/containerd/patches/default/0001-microk8s-sideload-images-plugin.patch
================================================
From d703811ab64963a6d52e6ac98b6a33b26b13e020 Mon Sep 17 00:00:00 2001
From: Angelos Kolaitis <angelos.kolaitis@canonical.com>
Date: Mon, 10 Jul 2023 12:15:34 +0300
Subject: [PATCH] microk8s sideload images plugin

---
 cmd/containerd/builtins_microk8s.go |   6 ++
 microk8s_plugins/sideload.go        | 132 ++++++++++++++++++++++++++++
 2 files changed, 138 insertions(+)
 create mode 100644 cmd/containerd/builtins_microk8s.go
 create mode 100644 microk8s_plugins/sideload.go

diff --git a/cmd/containerd/builtins_microk8s.go b/cmd/containerd/builtins_microk8s.go
new file mode 100644
index 0000000..d9afc6f
--- /dev/null
+++ b/cmd/containerd/builtins_microk8s.go
@@ -0,0 +1,6 @@
+package main
+
+// register containerd microk8s plugins here
+import (
+	_ "github.com/containerd/containerd/microk8s_plugins"
+)
diff --git a/microk8s_plugins/sideload.go b/microk8s_plugins/sideload.go
new file mode 100644
index 0000000..3ac632e
--- /dev/null
+++ b/microk8s_plugins/sideload.go
@@ -0,0 +1,132 @@
+package microk8s
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"time"
+
+	"github.com/containerd/containerd"
+	"github.com/containerd/containerd/log"
+	"github.com/containerd/containerd/platforms"
+	"github.com/containerd/containerd/plugin"
+)
+
+const pluginName = "sideload-images"
+
+var logger = log.L.WithField("plugin", pluginName)
+
+type Config struct {
+	// Interval configures how frequently the plugin will look for new images found
+	// in the sources. If set to zero, images are only loaded during initial start.
+	Interval *time.Duration `toml:"interval"`
+
+	// Sources is a list of paths to look for .tar images.
+	// For example, `/var/snap/microk8s/common/etc/sideload`
+	Sources []string `toml:"sources"`
+
+	// Namespace the images will be loaded into, e.g. "k8s.io"
+	Namespace string `toml:"namespace"`
+}
+
+func (c *Config) SetDefaults() {
+	if c.Namespace == "" {
+		c.Namespace = "k8s.io"
+	}
+	if len(c.Sources) == 0 {
+		snapCommon := os.Getenv("SNAP_COMMON")
+		if snapCommon == "" {
+			snapCommon = "/var/snap/microk8s/common"
+		}
+		c.Sources = []string{filepath.Join(snapCommon, "etc", "sideload")}
+	}
+	if c.Interval == nil {
+		t := 5 * time.Second
+		c.Interval = &t
+	}
+}
+
+func init() {
+	c := &Config{}
+	plugin.Register(&plugin.Registration{
+		Type:   plugin.ServicePlugin,
+		ID:     pluginName,
+		Config: c,
+		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
+			config := ic.Config.(*Config)
+			config.SetDefaults()
+
+			logger.Debugf("Loaded config %#v", config)
+
+			if len(config.Sources) == 0 {
+				return nil, fmt.Errorf("no sources configured: %w", plugin.ErrSkipPlugin)
+			}
+
+			go func() {
+				// get a containerd client
+				var (
+					cl  *containerd.Client
+					err error
+				)
+				for cl == nil {
+					select {
+					case <-ic.Context.Done():
+						return
+					default:
+					}
+
+					cl, err = containerd.New(ic.Address, containerd.WithDefaultNamespace(config.Namespace), containerd.WithTimeout(2*time.Second))
+					if err != nil {
+						logger.Info("Failed to create containerd client")
+					}
+				}
+
+				for {
+				nextDir:
+					for _, dir := range c.Sources {
+						logger := logger.WithField("dir", dir)
+						logger.Debug("Looking for images")
+						files, err := filepath.Glob(filepath.Join(dir, "*.tar"))
+						if err != nil {
+							logger.WithError(err).Warn("Failed to look for images")
+							continue nextDir
+						}
+
+					nextFile:
+						for _, file := range files {
+							logger := logger.WithField("file", file)
+							r, err := os.Open(file)
+							if err != nil {
+								logger.WithError(err).Warn("Failed to open file")
+								continue nextFile
+							}
+							images, err := cl.Import(ic.Context, r, containerd.WithImportPlatform(platforms.Default()))
+							if err != nil {
+								logger.WithError(err).Error("Failed to import images")
+							} else {
+								logger.Infof("Imported %d images", len(images))
+								os.Rename(file, file+".loaded")
+							}
+							if closeErr := r.Close(); closeErr != nil {
+								logger.WithError(closeErr).Error("Failed to close reader")
+							}
+						}
+					}
+
+					// retry after interval, finish if interval is zero
+					if *c.Interval == 0 {
+						logger.Info("Plugin terminating")
+						return
+					}
+					select {
+					case <-ic.Context.Done():
+						return
+					case <-time.After(*c.Interval):
+					}
+				}
+			}()
+
+			return nil, nil
+		},
+	})
+}
--
2.34.1


================================================
FILE: build-scripts/components/containerd/patches/v2.1.3/0001-microk8s-sideload-images-plugin.patch
================================================
From 7f26b3e013169510867383f09358b2d91641ad9f Mon Sep 17 00:00:00 2001
From: Angelos Kolaitis <angelos.kolaitis@canonical.com>
Date: Mon, 10 Jul 2023 12:15:34 +0300
Subject: [PATCH] microk8s sideload images plugin

---
 cmd/containerd/builtins_microk8s.go |   6 ++
 microk8s_plugins/sideload.go        | 142 ++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+)
 create mode 100644 cmd/containerd/builtins_microk8s.go
 create mode 100644 microk8s_plugins/sideload.go

diff --git a/cmd/containerd/builtins_microk8s.go b/cmd/containerd/builtins_microk8s.go
new file mode 100644
index 000000000..c215987fa
--- /dev/null
+++ b/cmd/containerd/builtins_microk8s.go
@@ -0,0 +1,6 @@
+package main
+
+// register containerd microk8s plugins here
+import (
+	_ "github.com/containerd/containerd/v2/microk8s_plugins"
+)
diff --git a/microk8s_plugins/sideload.go b/microk8s_plugins/sideload.go
new file mode 100644
index 000000000..a6d97c8a3
--- /dev/null
+++ b/microk8s_plugins/sideload.go
@@ -0,0 +1,142 @@
+package microk8s
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"time"
+
+	containerd "github.com/containerd/containerd/v2/client"
+	"github.com/containerd/containerd/v2/pkg/namespaces"
+	"github.com/containerd/containerd/v2/plugins"
+	"github.com/containerd/log"
+	"github.com/containerd/platforms"
+	"github.com/containerd/plugin"
+	"github.com/containerd/plugin/registry"
+)
+
+const pluginName = "sideload-images"
+
+var logger = log.L.WithField("plugin", pluginName)
+
+type Config struct {
+	// Interval configures how frequently the plugin will look for new images found
+	// in the sources. If set to zero, images are only loaded during initial start.
+	Interval *time.Duration `toml:"interval"`
+
+	// Sources is a list of paths to look for .tar images.
+	// For example, `/var/snap/microk8s/common/etc/sideload`
+	Sources []string `toml:"sources"`
+
+	// Namespace the images will be loaded into, e.g. "k8s.io"
+	Namespace string `toml:"namespace"`
+}
+
+func (c *Config) SetDefaults() {
+	if c.Namespace == "" {
+		c.Namespace = "k8s.io"
+	}
+	if len(c.Sources) == 0 {
+		snapCommon := os.Getenv("SNAP_COMMON")
+		if snapCommon == "" {
+			snapCommon = "/var/snap/microk8s/common"
+		}
+		c.Sources = []string{filepath.Join(snapCommon, "etc", "sideload")}
+	}
+	if c.Interval == nil {
+		t := 5 * time.Second
+		c.Interval = &t
+	}
+}
+
+func init() {
+	c := &Config{}
+	registry.Register(&plugin.Registration{
+		Type:   plugins.ServicePlugin,
+		ID:     pluginName,
+		Config: c,
+		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
+			config := ic.Config.(*Config)
+			config.SetDefaults()
+
+			logger.Debugf("Loaded config %#v", config)
+
+			if len(config.Sources) == 0 {
+				return nil, fmt.Errorf("no sources configured: %w", plugin.ErrSkipPlugin)
+			}
+
+			go func() {
+				// get a containerd client
+				var (
+					cl  *containerd.Client
+					err error
+				)
+				for cl == nil {
+					select {
+					case <-ic.Context.Done():
+						return
+					default:
+					}
+
+					cl, err = containerd.New(
+						"",
+						containerd.WithDefaultNamespace(config.Namespace),
+						containerd.WithDefaultPlatform(platforms.Default()),
+						containerd.WithInMemoryServices(ic),
+						containerd.WithTimeout(2*time.Second),
+					)
+					if err != nil {
+						logger.Info("Failed to create containerd client")
+					}
+				}
+
+				for {
+				nextDir:
+					for _, dir := range c.Sources {
+						logger := logger.WithField("dir", dir)
+						logger.Debug("Looking for images")
+						files, err := filepath.Glob(filepath.Join(dir, "*.tar"))
+						if err != nil {
+							logger.WithError(err).Warn("Failed to look for images")
+							continue nextDir
+						}
+
+					nextFile:
+						for _, file := range files {
+							logger := logger.WithField("file", file)
+							r, err := os.Open(file)
+							if err != nil {
+								logger.WithError(err).Warn("Failed to open file")
+								continue nextFile
+							}
+							ctx := namespaces.WithNamespace(ic.Context, config.Namespace)
+							images, err := cl.Import(ctx, r, containerd.WithImportPlatform(platforms.DefaultStrict()))
+							if err != nil {
+								logger.WithError(err).Error("Failed to import images")
+							} else {
+								logger.Infof("Imported %d images", len(images))
+								os.Rename(file, file+".loaded")
+							}
+							if closeErr := r.Close(); closeErr != nil {
+								logger.WithError(closeErr).Error("Failed to close reader")
+							}
+						}
+					}
+
+					// retry after interval, finish if interval is zero
+					if *c.Interval == 0 {
+						logger.Info("Plugin terminating")
+						return
+					}
+					select {
+					case <-ic.Context.Done():
+						return
+					case <-time.After(*c.Interval):
+					}
+				}
+			}()
+
+			return nil, nil
+		},
+	})
+}
-- 
2.43.0


================================================
FILE: build-scripts/components/containerd/repository
================================================
https://github.com/containerd/containerd


================================================
FILE: build-scripts/components/containerd/version.sh
================================================
#!/bin/bash

echo "v2.1.3"


================================================
FILE: build-scripts/components/etcd/build.sh
================================================
#!/bin/bash

export INSTALL="${1}"
mkdir -p "${INSTALL}"

GO_LDFLAGS="-s -w" GO_BUILD_FLAGS="-v" make build

for bin in etcd etcdctl; do
  cp "bin/${bin}" "${INSTALL}/${bin}"
done


================================================
FILE: build-scripts/components/etcd/repository
================================================
https://github.com/etcd-io/etcd


================================================
FILE: build-scripts/components/etcd/version.sh
================================================
#!/bin/bash

echo "v3.6.6"


================================================
FILE: build-scripts/components/flannel-cni-plugin/build.sh
================================================
#!/bin/bash

INSTALL="${1}/opt/cni/bin"
mkdir -p "${INSTALL}"

VERSION="${2}"

export CGO_ENABLED=0
go build -o dist/flannel -ldflags "-s -w -X github.com/flannel-io/cni-plugin/version.Version=${VERSION} -extldflags -static"

cp dist/flannel "${INSTALL}/flannel"


================================================
FILE: build-scripts/components/flannel-cni-plugin/repository
================================================
https://github.com/flannel-io/cni-plugin


================================================
FILE: build-scripts/components/flannel-cni-plugin/version.sh
================================================
#!/bin/bash

echo "v1.8.0-flannel2"


================================================
FILE: build-scripts/components/flanneld/build.sh
================================================
#!/bin/bash

INSTALL="${1}/opt/cni/bin"
mkdir -p "${INSTALL}"

VERSION="${2}"

export CGO_ENABLED=0
go build -o dist/flanneld -ldflags "-s -w -X github.com/flannel-io/flannel/version.Version=${VERSION} -extldflags -static"

cp dist/flanneld "${INSTALL}/flanneld"


================================================
FILE: build-scripts/components/flanneld/patches/default/0001-disable-udp-backend.patch
================================================
From 45ec777a0d113089453eca7fd2f7cb195555c6c9 Mon Sep 17 00:00:00 2001
From: MicroK8s builder bot <microk8s-builder-bot@canonical.com>
Date: Wed, 15 Feb 2023 15:52:51 +0000
Subject: [PATCH] disable udp backend

---
 main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.go b/main.go
index 064f58d..b591458 100644
--- a/main.go
+++ b/main.go
@@ -50,7 +50,7 @@ import (
 	_ "github.com/flannel-io/flannel/pkg/backend/ipip"
 	_ "github.com/flannel-io/flannel/pkg/backend/ipsec"
 	_ "github.com/flannel-io/flannel/pkg/backend/tencentvpc"
-	_ "github.com/flannel-io/flannel/pkg/backend/udp"
+	// _ "github.com/flannel-io/flannel/pkg/backend/udp"
 	_ "github.com/flannel-io/flannel/pkg/backend/vxlan"
 	_ "github.com/flannel-io/flannel/pkg/backend/wireguard"
 )
-- 
2.25.1


================================================
FILE: build-scripts/components/flanneld/repository
================================================
https://github.com/flannel-io/flannel


================================================
FILE: build-scripts/components/flanneld/version.sh
================================================
#!/bin/bash

echo "v0.27.4"


================================================
FILE: build-scripts/components/helm/build.sh
================================================
#!/bin/bash

VERSION="${2}"

INSTALL="${1}"
mkdir -p "${INSTALL}/bin"

make VERSION="${VERSION}"
cp bin/helm "${INSTALL}/bin/helm"

./bin/helm completion bash \
  | sed "s/complete -o default -F __start_helm helm/complete -o default -F __start_helm microk8s.helm/g" \
  | sed "s/complete -o default -o nospace -F __start_helm helm/complete -o default -o nospace -F __start_helm microk8s.helm/g" \
  > bin/helm.bash

./bin/helm completion bash \
  | sed "s/complete -o default -F __start_helm helm/complete -o default -F __start_helm microk8s.helm3/g" \
  | sed "s/complete -o default -o nospace -F __start_helm helm/complete -o default -o nospace -F __start_helm microk8s.helm3/g" \
  > bin/helm3.bash

cp bin/helm.bash "${INSTALL}/helm.bash"
cp bin/helm3.bash "${INSTALL}/helm3.bash"


================================================
FILE: build-scripts/components/helm/repository
================================================
https://github.com/helm/helm


================================================
FILE: build-scripts/components/helm/version.sh
================================================
#!/bin/bash

echo "v3.19.2"


================================================
FILE: build-scripts/components/k8s-dqlite/build.sh
================================================
#!/bin/bash

INSTALL="${1}/bin"
mkdir -p "${INSTALL}"

make static -j

cp bin/static/dqlite "${INSTALL}/dqlite"
cp bin/static/k8s-dqlite "${INSTALL}/k8s-dqlite"


================================================
FILE: build-scripts/components/k8s-dqlite/repository
================================================
https://github.com/canonical/k8s-dqlite


================================================
FILE: build-scripts/components/k8s-dqlite/version.sh
================================================
#!/bin/bash

echo "v1.8.1"


================================================
FILE: build-scripts/components/kubernetes/build.sh
================================================
#!/bin/bash -x

INSTALL="${1}"

export KUBE_GIT_VERSION_FILE="${PWD}/.version.sh"

for app in kubectl kubelite; do
  make WHAT="cmd/${app}" KUBE_STATIC_OVERRIDES=kubelite
  cp _output/bin/"${app}" "${INSTALL}/${app}"
done

_output/bin/kubectl completion bash \
  | sed "s/complete -o default -F __start_kubectl kubectl/complete -o default -F __start_kubectl microk8s.kubectl/g" \
  | sed "s/complete -o default -o nospace -F __start_kubectl kubectl/complete -o default -o nospace -F __start_kubectl microk8s.kubectl/g" \
  > _output/kubectl.bash

cp _output/kubectl.bash "${INSTALL}/kubectl.bash"


================================================
FILE: build-scripts/components/kubernetes/patches/v1.27.0/0000-Kubelite-integration.patch
================================================
From d0ae18d074db5ff361f363073f32b2f30c7a3686 Mon Sep 17 00:00:00 2001
From: Konstantinos Tsakalozos <kos.tsakalozos@canonical.com>
Date: Wed, 3 Mar 2021 18:19:37 +0200
Subject: [PATCH] Kubelite integration

---
 cmd/kube-apiserver/app/server.go    |  9 +++-
 cmd/kube-scheduler/app/server.go    |  6 ++-
 cmd/kubelet/app/server.go           | 13 +++--
 cmd/kubelite/app/daemons/daemon.go  | 84 +++++++++++++++++++++++++++++
 cmd/kubelite/app/options/options.go | 79 +++++++++++++++++++++++++++
 cmd/kubelite/app/server.go          | 79 +++++++++++++++++++++++++++
 cmd/kubelite/kubelite.go            | 28 ++++++++++
 pkg/volume/csi/csi_plugin.go        | 10 ++--
 8 files changed, 297 insertions(+), 11 deletions(-)
 create mode 100644 cmd/kubelite/app/daemons/daemon.go
 create mode 100644 cmd/kubelite/app/options/options.go
 create mode 100644 cmd/kubelite/app/server.go
 create mode 100644 cmd/kubelite/kubelite.go

diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go
index fc36d044dbe..cffb7c35a3c 100644
--- a/cmd/kube-apiserver/app/server.go
+++ b/cmd/kube-apiserver/app/server.go
@@ -89,7 +89,7 @@ func init() {
 }

 // NewAPIServerCommand creates a *cobra.Command object with default parameters
-func NewAPIServerCommand() *cobra.Command {
+func NewAPIServerCommand(stopCh... <- chan struct{}) *cobra.Command {
 	s := options.NewServerRunOptions()
 	cmd := &cobra.Command{
 		Use: "kube-apiserver",
@@ -129,7 +129,12 @@ cluster's shared state through which all other components interact.`,
 			}
 			// add feature enablement metrics
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
-			return Run(completedOptions, genericapiserver.SetupSignalHandler())
+
+			if len(stopCh) != 0 {
+				return Run(completedOptions, stopCh[0])
+			} else {
+				return Run(completedOptions, genericapiserver.SetupSignalHandler())
+			}
 		},
 		Args: func(cmd *cobra.Command, args []string) error {
 			for _, arg := range args {
diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go
index 8d01f3b7670..44ac7f69328 100644
--- a/cmd/kube-scheduler/app/server.go
+++ b/cmd/kube-scheduler/app/server.go
@@ -132,7 +132,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go func() {
-		stopCh := server.SetupSignalHandler()
+                c := cmd.Context()
+                if c == nil {
+                        c = server.SetupSignalContext()
+                }
+                stopCh := c.Done()
 		<-stopCh
 		cancel()
 	}()
diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go
index 9444f136866..8ca88f64d04 100644
--- a/cmd/kubelet/app/server.go
+++ b/cmd/kubelet/app/server.go
@@ -120,7 +120,7 @@ const (
 )

 // NewKubeletCommand creates a *cobra.Command object with default parameters
-func NewKubeletCommand() *cobra.Command {
+func NewKubeletCommand(ctx ...context.Context) *cobra.Command {
 	cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
 	cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
 	kubeletFlags := options.NewKubeletFlags()
@@ -250,6 +250,12 @@ HTTP server: The kubelet can also listen for HTTP and respond to a simple API
 			if err := checkPermissions(); err != nil {
 				klog.ErrorS(err, "kubelet running with insufficient permissions")
 			}
+			runctx := context.Background()
+			if len(ctx) == 0 {
+				runctx = genericapiserver.SetupSignalContext()
+			} else {
+				runctx = ctx[0]
+			}

 			// make the kubelet's config safe for logging
 			config := kubeletServer.KubeletConfiguration.DeepCopy()
@@ -259,12 +265,9 @@ HTTP server: The kubelet can also listen for HTTP and respond to a simple API
 			// log the kubelet's config for inspection
 			klog.V(5).InfoS("KubeletConfiguration", "configuration", config)

-			// set up signal context for kubelet shutdown
-			ctx := genericapiserver.SetupSignalContext()
-
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
 			// run the kubelet
-			return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
+			return Run(runctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
 		},
 	}

diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go
new file mode 100644
index 00000000000..dbef03cf07e
--- /dev/null
+++ b/cmd/kubelite/app/daemons/daemon.go
@@ -0,0 +1,84 @@
+package daemon
+
+import (
+	"context"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/clientcmd"
+	"k8s.io/klog/v2"
+	genericcontrollermanager "k8s.io/controller-manager/app"
+	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
+	controller "k8s.io/kubernetes/cmd/kube-controller-manager/app"
+	proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
+	scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
+	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
+
+	"time"
+)
+
+func StartControllerManager(args []string, ctx context.Context) {
+	command := controller.NewControllerManagerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Controller Manager")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Controller Manager exited %v", err)
+	}
+	klog.Info("Stopping Controller Manager")
+}
+
+func StartScheduler(args []string, ctx context.Context) {
+	command := scheduler.NewSchedulerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Scheduler")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Scheduler exited %v", err)
+	}
+	klog.Info("Stopping Scheduler")
+}
+
+func StartProxy(args []string) {
+	command := proxy.NewProxyCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Proxy")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Proxy exited %v", err)
+	}
+	klog.Info("Stopping Proxy")
+}
+
+func StartKubelet(args []string, ctx context.Context) {
+	command := kubelet.NewKubeletCommand(ctx)
+	command.SetArgs(args)
+
+	klog.Info("Starting Kubelet")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Kubelet exited %v", err)
+	}
+	klog.Info("Stopping Kubelet")
+}
+
+func StartAPIServer(args []string, ctx <-chan struct{}) {
+	command := apiserver.NewAPIServerCommand(ctx)
+	command.SetArgs(args)
+	klog.Info("Starting API Server")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("API Server exited %v", err)
+	}
+	klog.Info("Stopping API Server")
+}
+
+func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) {
+	klog.Info("Waiting for the API server")
+	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath)
+	if err != nil {
+		klog.Fatalf("could not find the cluster's kubeconfig file %v", err)
+	}
+	// create the client
+	client, err := kubernetes.NewForConfig(config)
+	if err != nil {
+		klog.Fatalf("could not create client to the cluster %v", err)
+	}
+	genericcontrollermanager.WaitForAPIServer(client, timeout)
+}
\ No newline at end of file
diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go
new file mode 100644
index 00000000000..80f1d8b09fc
--- /dev/null
+++ b/cmd/kubelite/app/options/options.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package options
+
+import (
+	"bufio"
+	"k8s.io/klog/v2"
+	"os"
+	"strings"
+)
+
+// Options has all the params needed to run a Kubelite
+type Options struct {
+	SchedulerArgsFile         string
+	ControllerManagerArgsFile string
+	ProxyArgsFile             string
+	KubeletArgsFile           string
+	APIServerArgsFile         string
+	KubeconfigFile    		  string
+	StartControlPlane		  bool
+}
+
+func NewOptions() (*Options){
+	o := Options{
+		"/var/snap/microk8s/current/args/kube-scheduler",
+		"/var/snap/microk8s/current/args/kube-controller-manager",
+		"/var/snap/microk8s/current/args/kube-proxy",
+		"/var/snap/microk8s/current/args/kubelet",
+		"/var/snap/microk8s/current/args/kube-apiserver",
+		"/var/snap/microk8s/current/credentials/client.config",
+		true,
+	}
+	return &o
+}
+
+func ReadArgsFromFile(filename string) []string {
+	var args []string
+	file, err := os.Open(filename)
+	if err != nil {
+		klog.Fatalf("Failed to open arguments file %v", err)
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		line = strings.TrimSpace(line)
+		// ignore lines with # and empty lines
+		if len(line) <= 0 || strings.HasPrefix(line, "#") {
+			continue
+		}
+		// remove " and '
+		for _, r := range "\"'" {
+			line = strings.ReplaceAll(line, string(r), "")
+		}
+		for _, part := range strings.Split(line, " ") {
+
+			args = append(args, os.ExpandEnv(part))
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		klog.Fatalf("Failed to read arguments file %v", err)
+	}
+	return args
+}
diff --git a/cmd/kubelite/app/server.go b/cmd/kubelite/app/server.go
new file mode 100644
index 00000000000..e7452a09e3e
--- /dev/null
+++ b/cmd/kubelite/app/server.go
@@ -0,0 +1,79 @@
+/*
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package app
+
+import (
+	"fmt"
+	"github.com/spf13/cobra"
+	genericapiserver "k8s.io/apiserver/pkg/server"
+	daemon "k8s.io/kubernetes/cmd/kubelite/app/daemons"
+	"k8s.io/kubernetes/cmd/kubelite/app/options"
+	"os"
+	"time"
+)
+
+var opts = options.NewOptions()
+
+// liteCmd represents the base command when called without any subcommands
+var liteCmd = &cobra.Command{
+	Use:   "kubelite",
+	Short: "Single server kubernetes",
+	Long: `A single server that spawns all other kubernetes servers as threads`,
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	Run: func(cmd *cobra.Command, args []string) {
+		ctx := genericapiserver.SetupSignalContext()
+
+		if opts.StartControlPlane {
+			apiserverArgs := options.ReadArgsFromFile(opts.APIServerArgsFile)
+			go daemon.StartAPIServer(apiserverArgs, ctx.Done())
+			daemon.WaitForAPIServer(opts.KubeconfigFile, 360 * time.Second)
+
+			controllerArgs := options.ReadArgsFromFile(opts.ControllerManagerArgsFile)
+			go daemon.StartControllerManager(controllerArgs, ctx)
+
+			schedulerArgs := options.ReadArgsFromFile(opts.SchedulerArgsFile)
+			go daemon.StartScheduler(schedulerArgs, ctx)
+		}
+
+		proxyArgs := options.ReadArgsFromFile(opts.ProxyArgsFile)
+		go daemon.StartProxy(proxyArgs)
+
+		kubeletArgs := options.ReadArgsFromFile(opts.KubeletArgsFile)
+		daemon.StartKubelet(kubeletArgs, ctx)
+	},
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the liteCmd.
+func Execute() {
+	if err := liteCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func init() {
+	cobra.OnInitialize()
+
+	liteCmd.Flags().StringVar(&opts.SchedulerArgsFile, "scheduler-args-file", opts.SchedulerArgsFile, "file with the arguments for the scheduler")
+	liteCmd.Flags().StringVar(&opts.ControllerManagerArgsFile, "controller-manager-args-file", opts.ControllerManagerArgsFile, "file with the arguments for the controller manager")
+	liteCmd.Flags().StringVar(&opts.ProxyArgsFile, "proxy-args-file", opts.ProxyArgsFile , "file with the arguments for kube-proxy")
+	liteCmd.Flags().StringVar(&opts.KubeletArgsFile, "kubelet-args-file", opts.KubeletArgsFile, "file with the arguments for kubelet")
+	liteCmd.Flags().StringVar(&opts.APIServerArgsFile, "apiserver-args-file", opts.APIServerArgsFile, "file with the arguments for the API server")
+	liteCmd.Flags().StringVar(&opts.KubeconfigFile , "kubeconfig-file", opts.KubeconfigFile, "the kubeconfig file to use to healthcheck the API server")
+	liteCmd.Flags().BoolVar(&opts.StartControlPlane, "start-control-plane", opts.StartControlPlane, "start the control plane (API server, scheduler and controller manager)")
+}
diff --git a/cmd/kubelite/kubelite.go b/cmd/kubelite/kubelite.go
new file mode 100644
index 00000000000..667b24f68e6
--- /dev/null
+++ b/cmd/kubelite/kubelite.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+	"github.com/spf13/pflag"
+	cliflag "k8s.io/component-base/cli/flag"
+	"math/rand"
+	"time"
+
+	"k8s.io/component-base/logs"
+	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin
+	_ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
+	"k8s.io/kubernetes/cmd/kubelite/app"
+)
+
+func main() {
+	println("Starting kubelite")
+	rand.Seed(time.Now().UnixNano())
+	// TODO: once we switch everything over to Cobra commands, we can go back to calling
+	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
+	// normalize func and add the go flag set by hand.
+	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
+	// utilflag.InitFlags()
+	logs.InitLogs()
+	defer logs.FlushLogs()
+
+	app.Execute()
+	println("Stopping kubelite")
+}
diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go
index ce7a543c94f..a8094f878d6 100644
--- a/pkg/volume/csi/csi_plugin.go
+++ b/pkg/volume/csi/csi_plugin.go
@@ -240,18 +240,22 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
 	}

 	// Initializing the label management channels
-	nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
+	localNim := nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)

 	// This function prevents Kubelet from posting Ready status until CSINode
 	// is both installed and initialized
-	if err := initializeCSINode(host); err != nil {
+	if err := initializeCSINode(host, localNim); err != nil {
 		return errors.New(log("failed to initialize CSINode: %v", err))
 	}

+	if _, ok := host.(volume.KubeletVolumeHost); ok {
+		nim = localNim
+	}
+
 	return nil
 }

-func initializeCSINode(host volume.VolumeHost) error {
+func initializeCSINode(host volume.VolumeHost, nim nodeinfomanager.Interface) error {
 	kvh, ok := host.(volume.KubeletVolumeHost)
 	if !ok {
 		klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
--
2.34.1


================================================
FILE: build-scripts/components/kubernetes/patches/v1.27.0/0001-Unix-socket-skip-validation-in-component-status.patch
================================================
From dd1db952eab13912a55207c81a2ac267909677ac Mon Sep 17 00:00:00 2001
From: Konstantinos Tsakalozos <kos.tsakalozos@canonical.com>
Date: Tue, 24 Aug 2021 11:17:19 +0300
Subject: [PATCH] Unix socket skip validation in component status

---
 pkg/registry/core/rest/storage_core.go | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/pkg/registry/core/rest/storage_core.go b/pkg/registry/core/rest/storage_core.go
index 1f915c32d4b..0bb7f1a9bf9 100644
--- a/pkg/registry/core/rest/storage_core.go
+++ b/pkg/registry/core/rest/storage_core.go
@@ -350,6 +350,12 @@ func (s componentStatusStorage) serversToValidate() map[string]*componentstatus.
 			klog.Errorf("Failed to parse etcd url for validation: %v", err)
 			continue
 		}
+
+		if etcdUrl.Scheme == "unix" {
+			klog.Infof("Socket etcd endpoint detected. Will not validate")
+			continue
+		}
+
 		var port int
 		var addr string
 		if strings.Contains(etcdUrl.Host, ":") {
--
2.25.1


================================================
FILE: build-scripts/components/kubernetes/patches/v1.27.4/0000-Kubelite-integration.patch
================================================
From 3162aa9df25819b60a3c0a3b044394639d55280c Mon Sep 17 00:00:00 2001
From: Konstantinos Tsakalozos <kos.tsakalozos@canonical.com>
Date: Wed, 3 Mar 2021 18:19:37 +0200
Subject: [PATCH] Kubelite integration

---
 cmd/kube-apiserver/app/server.go    |  9 +++-
 cmd/kube-scheduler/app/server.go    |  6 ++-
 cmd/kubelet/app/server.go           | 13 +++--
 cmd/kubelite/app/daemons/daemon.go  | 84 +++++++++++++++++++++++++++++
 cmd/kubelite/app/options/options.go | 79 +++++++++++++++++++++++++++
 cmd/kubelite/app/server.go          | 79 +++++++++++++++++++++++++++
 cmd/kubelite/kubelite.go            | 28 ++++++++++
 pkg/volume/csi/csi_plugin.go        | 10 ++--
 8 files changed, 297 insertions(+), 11 deletions(-)
 create mode 100644 cmd/kubelite/app/daemons/daemon.go
 create mode 100644 cmd/kubelite/app/options/options.go
 create mode 100644 cmd/kubelite/app/server.go
 create mode 100644 cmd/kubelite/kubelite.go

diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go
index b021bac2574..8d5a1bad8ed 100644
--- a/cmd/kube-apiserver/app/server.go
+++ b/cmd/kube-apiserver/app/server.go
@@ -76,7 +76,7 @@ func init() {
 }

 // NewAPIServerCommand creates a *cobra.Command object with default parameters
-func NewAPIServerCommand() *cobra.Command {
+func NewAPIServerCommand(stopCh... <- chan struct{}) *cobra.Command {
 	s := options.NewServerRunOptions()
 	cmd := &cobra.Command{
 		Use: "kube-apiserver",
@@ -116,7 +116,12 @@ cluster's shared state through which all other components interact.`,
 			}
 			// add feature enablement metrics
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
-			return Run(completedOptions, genericapiserver.SetupSignalHandler())
+
+			if len(stopCh) != 0 {
+				return Run(completedOptions, stopCh[0])
+			} else {
+				return Run(completedOptions, genericapiserver.SetupSignalHandler())
+			}
 		},
 		Args: func(cmd *cobra.Command, args []string) error {
 			for _, arg := range args {
diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go
index c48b09a420d..b7f273b02ac 100644
--- a/cmd/kube-scheduler/app/server.go
+++ b/cmd/kube-scheduler/app/server.go
@@ -132,7 +132,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go func() {
-		stopCh := server.SetupSignalHandler()
+                c := cmd.Context()
+                if c == nil {
+                        c = server.SetupSignalContext()
+                }
+                stopCh := c.Done()
 		<-stopCh
 		cancel()
 	}()
diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go
index 742524e325f..561cbf68868 100644
--- a/cmd/kubelet/app/server.go
+++ b/cmd/kubelet/app/server.go
@@ -122,7 +122,7 @@ const (
 )

 // NewKubeletCommand creates a *cobra.Command object with default parameters
-func NewKubeletCommand() *cobra.Command {
+func NewKubeletCommand(ctx ...context.Context) *cobra.Command {
 	cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
 	cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
 	kubeletFlags := options.NewKubeletFlags()
@@ -249,6 +249,12 @@ is checked every 20 seconds (also configurable with a flag).`,
 			if err := checkPermissions(); err != nil {
 				klog.ErrorS(err, "kubelet running with insufficient permissions")
 			}
+			runctx := context.Background()
+			if len(ctx) == 0 {
+				runctx = genericapiserver.SetupSignalContext()
+			} else {
+				runctx = ctx[0]
+			}

 			// make the kubelet's config safe for logging
 			config := kubeletServer.KubeletConfiguration.DeepCopy()
@@ -258,12 +264,9 @@ is checked every 20 seconds (also configurable with a flag).`,
 			// log the kubelet's config for inspection
 			klog.V(5).InfoS("KubeletConfiguration", "configuration", klog.Format(config))

-			// set up signal context for kubelet shutdown
-			ctx := genericapiserver.SetupSignalContext()
-
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
 			// run the kubelet
-			return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
+			return Run(runctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
 		},
 	}

diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go
new file mode 100644
index 00000000000..dbef03cf07e
--- /dev/null
+++ b/cmd/kubelite/app/daemons/daemon.go
@@ -0,0 +1,84 @@
+package daemon
+
+import (
+	"context"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/clientcmd"
+	"k8s.io/klog/v2"
+	genericcontrollermanager "k8s.io/controller-manager/app"
+	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
+	controller "k8s.io/kubernetes/cmd/kube-controller-manager/app"
+	proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
+	scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
+	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
+
+	"time"
+)
+
+func StartControllerManager(args []string, ctx context.Context) {
+	command := controller.NewControllerManagerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Controller Manager")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Controller Manager exited %v", err)
+	}
+	klog.Info("Stopping Controller Manager")
+}
+
+func StartScheduler(args []string, ctx context.Context) {
+	command := scheduler.NewSchedulerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Scheduler")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Scheduler exited %v", err)
+	}
+	klog.Info("Stopping Scheduler")
+}
+
+func StartProxy(args []string) {
+	command := proxy.NewProxyCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Proxy")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Proxy exited %v", err)
+	}
+	klog.Info("Stopping Proxy")
+}
+
+func StartKubelet(args []string, ctx context.Context) {
+	command := kubelet.NewKubeletCommand(ctx)
+	command.SetArgs(args)
+
+	klog.Info("Starting Kubelet")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Kubelet exited %v", err)
+	}
+	klog.Info("Stopping Kubelet")
+}
+
+func StartAPIServer(args []string, ctx <-chan struct{}) {
+	command := apiserver.NewAPIServerCommand(ctx)
+	command.SetArgs(args)
+	klog.Info("Starting API Server")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("API Server exited %v", err)
+	}
+	klog.Info("Stopping API Server")
+}
+
+func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) {
+	klog.Info("Waiting for the API server")
+	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath)
+	if err != nil {
+		klog.Fatalf("could not find the cluster's kubeconfig file %v", err)
+	}
+	// create the client
+	client, err := kubernetes.NewForConfig(config)
+	if err != nil {
+		klog.Fatalf("could not create client to the cluster %v", err)
+	}
+	genericcontrollermanager.WaitForAPIServer(client, timeout)
+}
\ No newline at end of file
diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go
new file mode 100644
index 00000000000..80f1d8b09fc
--- /dev/null
+++ b/cmd/kubelite/app/options/options.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package options
+
+import (
+	"bufio"
+	"k8s.io/klog/v2"
+	"os"
+	"strings"
+)
+
+// Options has all the params needed to run a Kubelite
+type Options struct {
+	SchedulerArgsFile         string
+	ControllerManagerArgsFile string
+	ProxyArgsFile             string
+	KubeletArgsFile           string
+	APIServerArgsFile         string
+	KubeconfigFile    		  string
+	StartControlPlane		  bool
+}
+
+func NewOptions() (*Options){
+	o := Options{
+		"/var/snap/microk8s/current/args/kube-scheduler",
+		"/var/snap/microk8s/current/args/kube-controller-manager",
+		"/var/snap/microk8s/current/args/kube-proxy",
+		"/var/snap/microk8s/current/args/kubelet",
+		"/var/snap/microk8s/current/args/kube-apiserver",
+		"/var/snap/microk8s/current/credentials/client.config",
+		true,
+	}
+	return &o
+}
+
+func ReadArgsFromFile(filename string) []string {
+	var args []string
+	file, err := os.Open(filename)
+	if err != nil {
+		klog.Fatalf("Failed to open arguments file %v", err)
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		line = strings.TrimSpace(line)
+		// ignore lines with # and empty lines
+		if len(line) <= 0 || strings.HasPrefix(line, "#") {
+			continue
+		}
+		// remove " and '
+		for _, r := range "\"'" {
+			line = strings.ReplaceAll(line, string(r), "")
+		}
+		for _, part := range strings.Split(line, " ") {
+
+			args = append(args, os.ExpandEnv(part))
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		klog.Fatalf("Failed to read arguments file %v", err)
+	}
+	return args
+}
diff --git a/cmd/kubelite/app/server.go b/cmd/kubelite/app/server.go
new file mode 100644
index 00000000000..e7452a09e3e
--- /dev/null
+++ b/cmd/kubelite/app/server.go
@@ -0,0 +1,79 @@
+/*
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package app
+
+import (
+	"fmt"
+	"github.com/spf13/cobra"
+	genericapiserver "k8s.io/apiserver/pkg/server"
+	daemon "k8s.io/kubernetes/cmd/kubelite/app/daemons"
+	"k8s.io/kubernetes/cmd/kubelite/app/options"
+	"os"
+	"time"
+)
+
+var opts = options.NewOptions()
+
+// liteCmd represents the base command when called without any subcommands
+var liteCmd = &cobra.Command{
+	Use:   "kubelite",
+	Short: "Single server kubernetes",
+	Long: `A single server that spawns all other kubernetes servers as threads`,
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	Run: func(cmd *cobra.Command, args []string) {
+		ctx := genericapiserver.SetupSignalContext()
+
+		if opts.StartControlPlane {
+			apiserverArgs := options.ReadArgsFromFile(opts.APIServerArgsFile)
+			go daemon.StartAPIServer(apiserverArgs, ctx.Done())
+			daemon.WaitForAPIServer(opts.KubeconfigFile, 360 * time.Second)
+
+			controllerArgs := options.ReadArgsFromFile(opts.ControllerManagerArgsFile)
+			go daemon.StartControllerManager(controllerArgs, ctx)
+
+			schedulerArgs := options.ReadArgsFromFile(opts.SchedulerArgsFile)
+			go daemon.StartScheduler(schedulerArgs, ctx)
+		}
+
+		proxyArgs := options.ReadArgsFromFile(opts.ProxyArgsFile)
+		go daemon.StartProxy(proxyArgs)
+
+		kubeletArgs := options.ReadArgsFromFile(opts.KubeletArgsFile)
+		daemon.StartKubelet(kubeletArgs, ctx)
+	},
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the liteCmd.
+func Execute() {
+	if err := liteCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func init() {
+	cobra.OnInitialize()
+
+	liteCmd.Flags().StringVar(&opts.SchedulerArgsFile, "scheduler-args-file", opts.SchedulerArgsFile, "file with the arguments for the scheduler")
+	liteCmd.Flags().StringVar(&opts.ControllerManagerArgsFile, "controller-manager-args-file", opts.ControllerManagerArgsFile, "file with the arguments for the controller manager")
+	liteCmd.Flags().StringVar(&opts.ProxyArgsFile, "proxy-args-file", opts.ProxyArgsFile , "file with the arguments for kube-proxy")
+	liteCmd.Flags().StringVar(&opts.KubeletArgsFile, "kubelet-args-file", opts.KubeletArgsFile, "file with the arguments for kubelet")
+	liteCmd.Flags().StringVar(&opts.APIServerArgsFile, "apiserver-args-file", opts.APIServerArgsFile, "file with the arguments for the API server")
+	liteCmd.Flags().StringVar(&opts.KubeconfigFile , "kubeconfig-file", opts.KubeconfigFile, "the kubeconfig file to use to healthcheck the API server")
+	liteCmd.Flags().BoolVar(&opts.StartControlPlane, "start-control-plane", opts.StartControlPlane, "start the control plane (API server, scheduler and controller manager)")
+}
diff --git a/cmd/kubelite/kubelite.go b/cmd/kubelite/kubelite.go
new file mode 100644
index 00000000000..667b24f68e6
--- /dev/null
+++ b/cmd/kubelite/kubelite.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+	"github.com/spf13/pflag"
+	cliflag "k8s.io/component-base/cli/flag"
+	"math/rand"
+	"time"
+
+	"k8s.io/component-base/logs"
+	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin
+	_ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
+	"k8s.io/kubernetes/cmd/kubelite/app"
+)
+
+func main() {
+	println("Starting kubelite")
+	rand.Seed(time.Now().UnixNano())
+	// TODO: once we switch everything over to Cobra commands, we can go back to calling
+	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
+	// normalize func and add the go flag set by hand.
+	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
+	// utilflag.InitFlags()
+	logs.InitLogs()
+	defer logs.FlushLogs()
+
+	app.Execute()
+	println("Stopping kubelite")
+}
diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go
index 2556517276e..0b5ef45d083 100644
--- a/pkg/volume/csi/csi_plugin.go
+++ b/pkg/volume/csi/csi_plugin.go
@@ -243,18 +243,22 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
 	}

 	// Initializing the label management channels
-	nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
+	localNim := nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)

 	// This function prevents Kubelet from posting Ready status until CSINode
 	// is both installed and initialized
-	if err := initializeCSINode(host); err != nil {
+	if err := initializeCSINode(host, localNim); err != nil {
 		return errors.New(log("failed to initialize CSINode: %v", err))
 	}

+	if _, ok := host.(volume.KubeletVolumeHost); ok {
+		nim = localNim
+	}
+
 	return nil
 }

-func initializeCSINode(host volume.VolumeHost) error {
+func initializeCSINode(host volume.VolumeHost, nim nodeinfomanager.Interface) error {
 	kvh, ok := host.(volume.KubeletVolumeHost)
 	if !ok {
 		klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
--
2.34.1


================================================
FILE: build-scripts/components/kubernetes/patches/v1.28.0/0000-Kubelite-integration.patch
================================================
From 3162aa9df25819b60a3c0a3b044394639d55280c Mon Sep 17 00:00:00 2001
From: Konstantinos Tsakalozos <kos.tsakalozos@canonical.com>
Date: Wed, 3 Mar 2021 18:19:37 +0200
Subject: [PATCH] Kubelite integration

---
 cmd/kube-apiserver/app/server.go    |  9 +++-
 cmd/kube-scheduler/app/server.go    |  6 ++-
 cmd/kubelet/app/server.go           | 13 +++--
 cmd/kubelite/app/daemons/daemon.go  | 84 +++++++++++++++++++++++++++++
 cmd/kubelite/app/options/options.go | 79 +++++++++++++++++++++++++++
 cmd/kubelite/app/server.go          | 79 +++++++++++++++++++++++++++
 cmd/kubelite/kubelite.go            | 28 ++++++++++
 pkg/volume/csi/csi_plugin.go        | 10 ++--
 8 files changed, 297 insertions(+), 11 deletions(-)
 create mode 100644 cmd/kubelite/app/daemons/daemon.go
 create mode 100644 cmd/kubelite/app/options/options.go
 create mode 100644 cmd/kubelite/app/server.go
 create mode 100644 cmd/kubelite/kubelite.go

diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go
index b021bac2574..8d5a1bad8ed 100644
--- a/cmd/kube-apiserver/app/server.go
+++ b/cmd/kube-apiserver/app/server.go
@@ -76,7 +76,7 @@ func init() {
 }

 // NewAPIServerCommand creates a *cobra.Command object with default parameters
-func NewAPIServerCommand() *cobra.Command {
+func NewAPIServerCommand(stopCh... <- chan struct{}) *cobra.Command {
 	s := options.NewServerRunOptions()
 	cmd := &cobra.Command{
 		Use: "kube-apiserver",
@@ -116,7 +116,12 @@ cluster's shared state through which all other components interact.`,
 			}
 			// add feature enablement metrics
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
-			return Run(completedOptions, genericapiserver.SetupSignalHandler())
+
+			if len(stopCh) != 0 {
+				return Run(completedOptions, stopCh[0])
+			} else {
+				return Run(completedOptions, genericapiserver.SetupSignalHandler())
+			}
 		},
 		Args: func(cmd *cobra.Command, args []string) error {
 			for _, arg := range args {
diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go
index c48b09a420d..b7f273b02ac 100644
--- a/cmd/kube-scheduler/app/server.go
+++ b/cmd/kube-scheduler/app/server.go
@@ -132,7 +132,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go func() {
-		stopCh := server.SetupSignalHandler()
+                c := cmd.Context()
+                if c == nil {
+                        c = server.SetupSignalContext()
+                }
+                stopCh := c.Done()
 		<-stopCh
 		cancel()
 	}()
diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go
index 742524e325f..561cbf68868 100644
--- a/cmd/kubelet/app/server.go
+++ b/cmd/kubelet/app/server.go
@@ -122,7 +122,7 @@ const (
 )

 // NewKubeletCommand creates a *cobra.Command object with default parameters
-func NewKubeletCommand() *cobra.Command {
+func NewKubeletCommand(ctx ...context.Context) *cobra.Command {
 	cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
 	cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
 	kubeletFlags := options.NewKubeletFlags()
@@ -249,6 +249,12 @@ is checked every 20 seconds (also configurable with a flag).`,
 			if err := checkPermissions(); err != nil {
 				klog.ErrorS(err, "kubelet running with insufficient permissions")
 			}
+			runctx := context.Background()
+			if len(ctx) == 0 {
+				runctx = genericapiserver.SetupSignalContext()
+			} else {
+				runctx = ctx[0]
+			}

 			// make the kubelet's config safe for logging
 			config := kubeletServer.KubeletConfiguration.DeepCopy()
@@ -258,12 +264,9 @@ is checked every 20 seconds (also configurable with a flag).`,
 			// log the kubelet's config for inspection
 			klog.V(5).InfoS("KubeletConfiguration", "configuration", klog.Format(config))

-			// set up signal context for kubelet shutdown
-			ctx := genericapiserver.SetupSignalContext()
-
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
 			// run the kubelet
-			return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
+			return Run(runctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
 		},
 	}

diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go
new file mode 100644
index 00000000000..dbef03cf07e
--- /dev/null
+++ b/cmd/kubelite/app/daemons/daemon.go
@@ -0,0 +1,84 @@
+package daemon
+
+import (
+	"context"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/clientcmd"
+	"k8s.io/klog/v2"
+	genericcontrollermanager "k8s.io/controller-manager/app"
+	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
+	controller "k8s.io/kubernetes/cmd/kube-controller-manager/app"
+	proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
+	scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
+	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
+
+	"time"
+)
+
+func StartControllerManager(args []string, ctx context.Context) {
+	command := controller.NewControllerManagerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Controller Manager")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Controller Manager exited %v", err)
+	}
+	klog.Info("Stopping Controller Manager")
+}
+
+func StartScheduler(args []string, ctx context.Context) {
+	command := scheduler.NewSchedulerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Scheduler")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Scheduler exited %v", err)
+	}
+	klog.Info("Stopping Scheduler")
+}
+
+func StartProxy(args []string) {
+	command := proxy.NewProxyCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Proxy")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Proxy exited %v", err)
+	}
+	klog.Info("Stopping Proxy")
+}
+
+func StartKubelet(args []string, ctx context.Context) {
+	command := kubelet.NewKubeletCommand(ctx)
+	command.SetArgs(args)
+
+	klog.Info("Starting Kubelet")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Kubelet exited %v", err)
+	}
+	klog.Info("Stopping Kubelet")
+}
+
+func StartAPIServer(args []string, ctx <-chan struct{}) {
+	command := apiserver.NewAPIServerCommand(ctx)
+	command.SetArgs(args)
+	klog.Info("Starting API Server")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("API Server exited %v", err)
+	}
+	klog.Info("Stopping API Server")
+}
+
+func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) {
+	klog.Info("Waiting for the API server")
+	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath)
+	if err != nil {
+		klog.Fatalf("could not find the cluster's kubeconfig file %v", err)
+	}
+	// create the client
+	client, err := kubernetes.NewForConfig(config)
+	if err != nil {
+		klog.Fatalf("could not create client to the cluster %v", err)
+	}
+	genericcontrollermanager.WaitForAPIServer(client, timeout)
+}
\ No newline at end of file
diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go
new file mode 100644
index 00000000000..80f1d8b09fc
--- /dev/null
+++ b/cmd/kubelite/app/options/options.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package options
+
+import (
+	"bufio"
+	"k8s.io/klog/v2"
+	"os"
+	"strings"
+)
+
+// Options has all the params needed to run a Kubelite
+type Options struct {
+	SchedulerArgsFile         string
+	ControllerManagerArgsFile string
+	ProxyArgsFile             string
+	KubeletArgsFile           string
+	APIServerArgsFile         string
+	KubeconfigFile    		  string
+	StartControlPlane		  bool
+}
+
+func NewOptions() (*Options){
+	o := Options{
+		"/var/snap/microk8s/current/args/kube-scheduler",
+		"/var/snap/microk8s/current/args/kube-controller-manager",
+		"/var/snap/microk8s/current/args/kube-proxy",
+		"/var/snap/microk8s/current/args/kubelet",
+		"/var/snap/microk8s/current/args/kube-apiserver",
+		"/var/snap/microk8s/current/credentials/client.config",
+		true,
+	}
+	return &o
+}
+
+func ReadArgsFromFile(filename string) []string {
+	var args []string
+	file, err := os.Open(filename)
+	if err != nil {
+		klog.Fatalf("Failed to open arguments file %v", err)
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		line = strings.TrimSpace(line)
+		// ignore lines with # and empty lines
+		if len(line) <= 0 || strings.HasPrefix(line, "#") {
+			continue
+		}
+		// remove " and '
+		for _, r := range "\"'" {
+			line = strings.ReplaceAll(line, string(r), "")
+		}
+		for _, part := range strings.Split(line, " ") {
+
+			args = append(args, os.ExpandEnv(part))
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		klog.Fatalf("Failed to read arguments file %v", err)
+	}
+	return args
+}
diff --git a/cmd/kubelite/app/server.go b/cmd/kubelite/app/server.go
new file mode 100644
index 00000000000..e7452a09e3e
--- /dev/null
+++ b/cmd/kubelite/app/server.go
@@ -0,0 +1,79 @@
+/*
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package app
+
+import (
+	"fmt"
+	"github.com/spf13/cobra"
+	genericapiserver "k8s.io/apiserver/pkg/server"
+	daemon "k8s.io/kubernetes/cmd/kubelite/app/daemons"
+	"k8s.io/kubernetes/cmd/kubelite/app/options"
+	"os"
+	"time"
+)
+
+var opts = options.NewOptions()
+
+// liteCmd represents the base command when called without any subcommands
+var liteCmd = &cobra.Command{
+	Use:   "kubelite",
+	Short: "Single server kubernetes",
+	Long: `A single server that spawns all other kubernetes servers as threads`,
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	Run: func(cmd *cobra.Command, args []string) {
+		ctx := genericapiserver.SetupSignalContext()
+
+		if opts.StartControlPlane {
+			apiserverArgs := options.ReadArgsFromFile(opts.APIServerArgsFile)
+			go daemon.StartAPIServer(apiserverArgs, ctx.Done())
+			daemon.WaitForAPIServer(opts.KubeconfigFile, 360 * time.Second)
+
+			controllerArgs := options.ReadArgsFromFile(opts.ControllerManagerArgsFile)
+			go daemon.StartControllerManager(controllerArgs, ctx)
+
+			schedulerArgs := options.ReadArgsFromFile(opts.SchedulerArgsFile)
+			go daemon.StartScheduler(schedulerArgs, ctx)
+		}
+
+		proxyArgs := options.ReadArgsFromFile(opts.ProxyArgsFile)
+		go daemon.StartProxy(proxyArgs)
+
+		kubeletArgs := options.ReadArgsFromFile(opts.KubeletArgsFile)
+		daemon.StartKubelet(kubeletArgs, ctx)
+	},
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the liteCmd.
+func Execute() {
+	if err := liteCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func init() {
+	cobra.OnInitialize()
+
+	liteCmd.Flags().StringVar(&opts.SchedulerArgsFile, "scheduler-args-file", opts.SchedulerArgsFile, "file with the arguments for the scheduler")
+	liteCmd.Flags().StringVar(&opts.ControllerManagerArgsFile, "controller-manager-args-file", opts.ControllerManagerArgsFile, "file with the arguments for the controller manager")
+	liteCmd.Flags().StringVar(&opts.ProxyArgsFile, "proxy-args-file", opts.ProxyArgsFile , "file with the arguments for kube-proxy")
+	liteCmd.Flags().StringVar(&opts.KubeletArgsFile, "kubelet-args-file", opts.KubeletArgsFile, "file with the arguments for kubelet")
+	liteCmd.Flags().StringVar(&opts.APIServerArgsFile, "apiserver-args-file", opts.APIServerArgsFile, "file with the arguments for the API server")
+	liteCmd.Flags().StringVar(&opts.KubeconfigFile , "kubeconfig-file", opts.KubeconfigFile, "the kubeconfig file to use to healthcheck the API server")
+	liteCmd.Flags().BoolVar(&opts.StartControlPlane, "start-control-plane", opts.StartControlPlane, "start the control plane (API server, scheduler and controller manager)")
+}
diff --git a/cmd/kubelite/kubelite.go b/cmd/kubelite/kubelite.go
new file mode 100644
index 00000000000..667b24f68e6
--- /dev/null
+++ b/cmd/kubelite/kubelite.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+	"github.com/spf13/pflag"
+	cliflag "k8s.io/component-base/cli/flag"
+	"math/rand"
+	"time"
+
+	"k8s.io/component-base/logs"
+	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin
+	_ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
+	"k8s.io/kubernetes/cmd/kubelite/app"
+)
+
+func main() {
+	println("Starting kubelite")
+	rand.Seed(time.Now().UnixNano())
+	// TODO: once we switch everything over to Cobra commands, we can go back to calling
+	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
+	// normalize func and add the go flag set by hand.
+	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
+	// utilflag.InitFlags()
+	logs.InitLogs()
+	defer logs.FlushLogs()
+
+	app.Execute()
+	println("Stopping kubelite")
+}
diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go
index 2556517276e..0b5ef45d083 100644
--- a/pkg/volume/csi/csi_plugin.go
+++ b/pkg/volume/csi/csi_plugin.go
@@ -243,18 +243,22 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
 	}

 	// Initializing the label management channels
-	nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
+	localNim := nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)

 	// This function prevents Kubelet from posting Ready status until CSINode
 	// is both installed and initialized
-	if err := initializeCSINode(host); err != nil {
+	if err := initializeCSINode(host, localNim); err != nil {
 		return errors.New(log("failed to initialize CSINode: %v", err))
 	}

+	if _, ok := host.(volume.KubeletVolumeHost); ok {
+		nim = localNim
+	}
+
 	return nil
 }

-func initializeCSINode(host volume.VolumeHost) error {
+func initializeCSINode(host volume.VolumeHost, nim nodeinfomanager.Interface) error {
 	kvh, ok := host.(volume.KubeletVolumeHost)
 	if !ok {
 		klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
--
2.34.1


================================================
FILE: build-scripts/components/kubernetes/patches/v1.28.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch
================================================
From 55f4864d816c8e7ca0ebb39571dc88dbdf05eff2 Mon Sep 17 00:00:00 2001
From: Angelos Kolaitis <angelos.kolaitis@canonical.com>
Date: Thu, 27 Jul 2023 18:08:00 +0300
Subject: [PATCH] Set log reapply handling to ignore unchanged

---
 staging/src/k8s.io/component-base/logs/api/v1/options.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/staging/src/k8s.io/component-base/logs/api/v1/options.go b/staging/src/k8s.io/component-base/logs/api/v1/options.go
index 2db9b1f5382..e0824dcdc4e 100644
--- a/staging/src/k8s.io/component-base/logs/api/v1/options.go
+++ b/staging/src/k8s.io/component-base/logs/api/v1/options.go
@@ -64,7 +64,7 @@ func NewLoggingConfiguration() *LoggingConfiguration {
 // are no goroutines which might call logging functions. The default for ValidateAndApply
 // and ValidateAndApplyWithOptions is to return an error when called more than once.
 // Binaries and unit tests can override that behavior.
-var ReapplyHandling = ReapplyHandlingError
+var ReapplyHandling = ReapplyHandlingIgnoreUnchanged

 type ReapplyHandlingType int

--
2.34.1


================================================
FILE: build-scripts/components/kubernetes/patches/v1.31.0/0000-Kubelite-integration.patch
================================================
From d261b947963b9e808725a21e3d55e52c20826e22 Mon Sep 17 00:00:00 2001
From: Konstantinos Tsakalozos <kos.tsakalozos@canonical.com>
Date: Wed, 3 Mar 2021 18:19:37 +0200
Subject: [PATCH] Kubelite integration

---
 cmd/kube-apiserver/app/server.go    |  9 ++-
 cmd/kube-scheduler/app/server.go    |  6 +-
 cmd/kubelet/app/server.go           | 13 +++--
 cmd/kubelite/app/daemons/daemon.go  | 85 +++++++++++++++++++++++++++++
 cmd/kubelite/app/options/options.go | 79 +++++++++++++++++++++++++++
 cmd/kubelite/app/server.go          | 80 +++++++++++++++++++++++++++
 cmd/kubelite/kubelite.go            | 25 +++++++++
 pkg/volume/csi/csi_plugin.go        | 10 +++-
 8 files changed, 296 insertions(+), 11 deletions(-)
 create mode 100644 cmd/kubelite/app/daemons/daemon.go
 create mode 100644 cmd/kubelite/app/options/options.go
 create mode 100644 cmd/kubelite/app/server.go
 create mode 100644 cmd/kubelite/kubelite.go

diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go
index fad0f1e9579..5e291005671 100644
--- a/cmd/kube-apiserver/app/server.go
+++ b/cmd/kube-apiserver/app/server.go
@@ -63,7 +63,7 @@ func init() {
 }
 
 // NewAPIServerCommand creates a *cobra.Command object with default parameters
-func NewAPIServerCommand() *cobra.Command {
+func NewAPIServerCommand(ctx ...context.Context) *cobra.Command {
 	_, featureGate := utilversion.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(
 		utilversion.DefaultKubeComponent, utilversion.DefaultBuildEffectiveVersion(), utilfeature.DefaultMutableFeatureGate)
 	s := options.NewServerRunOptions()
@@ -119,7 +119,12 @@ cluster's shared state through which all other components interact.`,
 			return nil
 		},
 	}
-	cmd.SetContext(genericapiserver.SetupSignalContext())
+
+	if len(ctx) == 0 {
+		cmd.SetContext(genericapiserver.SetupSignalContext())
+	} else {
+		cmd.SetContext(ctx[0])
+	}
 
 	fs := cmd.Flags()
 	namedFlagSets := s.Flags()
diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go
index 7b08b119b4b..5d2a5a5f51a 100644
--- a/cmd/kube-scheduler/app/server.go
+++ b/cmd/kube-scheduler/app/server.go
@@ -145,7 +145,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go func() {
-		stopCh := server.SetupSignalHandler()
+                c := cmd.Context()
+                if c == nil {
+                        c = server.SetupSignalContext()
+                }
+                stopCh := c.Done()
 		<-stopCh
 		cancel()
 	}()
diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go
index 2d90030d210..666996e2ecb 100644
--- a/cmd/kubelet/app/server.go
+++ b/cmd/kubelet/app/server.go
@@ -129,7 +129,7 @@ const (
 )
 
 // NewKubeletCommand creates a *cobra.Command object with default parameters
-func NewKubeletCommand() *cobra.Command {
+func NewKubeletCommand(ctx ...context.Context) *cobra.Command {
 	cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
 	cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
 	kubeletFlags := options.NewKubeletFlags()
@@ -266,6 +266,12 @@ is checked every 20 seconds (also configurable with a flag).`,
 			if err := checkPermissions(); err != nil {
 				klog.ErrorS(err, "kubelet running with insufficient permissions")
 			}
+			runctx := context.Background()
+			if len(ctx) == 0 {
+				runctx = genericapiserver.SetupSignalContext()
+			} else {
+				runctx = ctx[0]
+			}
 
 			// make the kubelet's config safe for logging
 			config := kubeletServer.KubeletConfiguration.DeepCopy()
@@ -275,12 +281,9 @@ is checked every 20 seconds (also configurable with a flag).`,
 			// log the kubelet's config for inspection
 			klog.V(5).InfoS("KubeletConfiguration", "configuration", klog.Format(config))
 
-			// set up signal context for kubelet shutdown
-			ctx := genericapiserver.SetupSignalContext()
-
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
 			// run the kubelet
-			return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
+			return Run(runctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
 		},
 	}
 
diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go
new file mode 100644
index 00000000000..46c1af7fdb9
--- /dev/null
+++ b/cmd/kubelite/app/daemons/daemon.go
@@ -0,0 +1,85 @@
+package daemon
+
+import (
+	"context"
+
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/clientcmd"
+	genericcontrollermanager "k8s.io/controller-manager/app"
+	"k8s.io/klog/v2"
+	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
+	controller "k8s.io/kubernetes/cmd/kube-controller-manager/app"
+	proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
+	scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
+	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
+
+	"time"
+)
+
+func StartControllerManager(args []string, ctx context.Context) {
+	command := controller.NewControllerManagerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Controller Manager")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Controller Manager exited %v", err)
+	}
+	klog.Info("Stopping Controller Manager")
+}
+
+func StartScheduler(args []string, ctx context.Context) {
+	command := scheduler.NewSchedulerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Scheduler")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Scheduler exited %v", err)
+	}
+	klog.Info("Stopping Scheduler")
+}
+
+func StartProxy(args []string) {
+	command := proxy.NewProxyCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Proxy")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Proxy exited %v", err)
+	}
+	klog.Info("Stopping Proxy")
+}
+
+func StartKubelet(args []string, ctx context.Context) {
+	command := kubelet.NewKubeletCommand(ctx)
+	command.SetArgs(args)
+
+	klog.Info("Starting Kubelet")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Kubelet exited %v", err)
+	}
+	klog.Info("Stopping Kubelet")
+}
+
+func StartAPIServer(args []string, ctx context.Context) {
+	command := apiserver.NewAPIServerCommand(ctx)
+	command.SetArgs(args)
+	klog.Info("Starting API Server")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("API Server exited %v", err)
+	}
+	klog.Info("Stopping API Server")
+}
+
+func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) {
+	klog.Info("Waiting for the API server")
+	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath)
+	if err != nil {
+		klog.Fatalf("could not find the cluster's kubeconfig file %v", err)
+	}
+	// create the client
+	client, err := kubernetes.NewForConfig(config)
+	if err != nil {
+		klog.Fatalf("could not create client to the cluster %v", err)
+	}
+	genericcontrollermanager.WaitForAPIServer(client, timeout)
+}
diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go
new file mode 100644
index 00000000000..80f1d8b09fc
--- /dev/null
+++ b/cmd/kubelite/app/options/options.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package options
+
+import (
+	"bufio"
+	"k8s.io/klog/v2"
+	"os"
+	"strings"
+)
+
+// Options has all the params needed to run a Kubelite
+type Options struct {
+	SchedulerArgsFile         string
+	ControllerManagerArgsFile string
+	ProxyArgsFile             string
+	KubeletArgsFile           string
+	APIServerArgsFile         string
+	KubeconfigFile    		  string
+	StartControlPlane		  bool
+}
+
+func NewOptions() (*Options){
+	o := Options{
+		"/var/snap/microk8s/current/args/kube-scheduler",
+		"/var/snap/microk8s/current/args/kube-controller-manager",
+		"/var/snap/microk8s/current/args/kube-proxy",
+		"/var/snap/microk8s/current/args/kubelet",
+		"/var/snap/microk8s/current/args/kube-apiserver",
+		"/var/snap/microk8s/current/credentials/client.config",
+		true,
+	}
+	return &o
+}
+
+func ReadArgsFromFile(filename string) []string {
+	var args []string
+	file, err := os.Open(filename)
+	if err != nil {
+		klog.Fatalf("Failed to open arguments file %v", err)
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		line = strings.TrimSpace(line)
+		// ignore lines with # and empty lines
+		if len(line) <= 0 || strings.HasPrefix(line, "#") {
+			continue
+		}
+		// remove " and '
+		for _, r := range "\"'" {
+			line = strings.ReplaceAll(line, string(r), "")
+		}
+		for _, part := range strings.Split(line, " ") {
+
+			args = append(args, os.ExpandEnv(part))
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		klog.Fatalf("Failed to read arguments file %v", err)
+	}
+	return args
+}
diff --git a/cmd/kubelite/app/server.go b/cmd/kubelite/app/server.go
new file mode 100644
index 00000000000..4ff36cd6432
--- /dev/null
+++ b/cmd/kubelite/app/server.go
@@ -0,0 +1,80 @@
+/*
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package app
+
+import (
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/spf13/cobra"
+	genericapiserver "k8s.io/apiserver/pkg/server"
+	daemon "k8s.io/kubernetes/cmd/kubelite/app/daemons"
+	"k8s.io/kubernetes/cmd/kubelite/app/options"
+)
+
+var opts = options.NewOptions()
+
+// liteCmd represents the base command when called without any subcommands
+var liteCmd = &cobra.Command{
+	Use:   "kubelite",
+	Short: "Single server kubernetes",
+	Long:  `A single server that spawns all other kubernetes servers as threads`,
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	Run: func(cmd *cobra.Command, args []string) {
+		ctx := genericapiserver.SetupSignalContext()
+
+		if opts.StartControlPlane {
+			apiserverArgs := options.ReadArgsFromFile(opts.APIServerArgsFile)
+			go daemon.StartAPIServer(apiserverArgs, ctx)
+			daemon.WaitForAPIServer(opts.KubeconfigFile, 360*time.Second)
+
+			controllerArgs := options.ReadArgsFromFile(opts.ControllerManagerArgsFile)
+			go daemon.StartControllerManager(controllerArgs, ctx)
+
+			schedulerArgs := options.ReadArgsFromFile(opts.SchedulerArgsFile)
+			go daemon.StartScheduler(schedulerArgs, ctx)
+		}
+
+		proxyArgs := options.ReadArgsFromFile(opts.ProxyArgsFile)
+		go daemon.StartProxy(proxyArgs)
+
+		kubeletArgs := options.ReadArgsFromFile(opts.KubeletArgsFile)
+		daemon.StartKubelet(kubeletArgs, ctx)
+	},
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the liteCmd.
+func Execute() {
+	if err := liteCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func init() {
+	cobra.OnInitialize()
+
+	liteCmd.Flags().StringVar(&opts.SchedulerArgsFile, "scheduler-args-file", opts.SchedulerArgsFile, "file with the arguments for the scheduler")
+	liteCmd.Flags().StringVar(&opts.ControllerManagerArgsFile, "controller-manager-args-file", opts.ControllerManagerArgsFile, "file with the arguments for the controller manager")
+	liteCmd.Flags().StringVar(&opts.ProxyArgsFile, "proxy-args-file", opts.ProxyArgsFile, "file with the arguments for kube-proxy")
+	liteCmd.Flags().StringVar(&opts.KubeletArgsFile, "kubelet-args-file", opts.KubeletArgsFile, "file with the arguments for kubelet")
+	liteCmd.Flags().StringVar(&opts.APIServerArgsFile, "apiserver-args-file", opts.APIServerArgsFile, "file with the arguments for the API server")
+	liteCmd.Flags().StringVar(&opts.KubeconfigFile, "kubeconfig-file", opts.KubeconfigFile, "the kubeconfig file to use to healthcheck the API server")
+	liteCmd.Flags().BoolVar(&opts.StartControlPlane, "start-control-plane", opts.StartControlPlane, "start the control plane (API server, scheduler and controller manager)")
+}
diff --git a/cmd/kubelite/kubelite.go b/cmd/kubelite/kubelite.go
new file mode 100644
index 00000000000..30ab604f480
--- /dev/null
+++ b/cmd/kubelite/kubelite.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+	"github.com/spf13/pflag"
+	cliflag "k8s.io/component-base/cli/flag"
+
+	"k8s.io/component-base/logs"
+	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin
+	_ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
+	"k8s.io/kubernetes/cmd/kubelite/app"
+)
+
+func main() {
+	println("Starting kubelite")
+	// TODO: once we switch everything over to Cobra commands, we can go back to calling
+	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
+	// normalize func and add the go flag set by hand.
+	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
+	// utilflag.InitFlags()
+	logs.InitLogs()
+	defer logs.FlushLogs()
+
+	app.Execute()
+	println("Stopping kubelite")
+}
diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go
index fec8a34b4d3..523eb78f05c 100644
--- a/pkg/volume/csi/csi_plugin.go
+++ b/pkg/volume/csi/csi_plugin.go
@@ -253,18 +253,22 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
 	}
 
 	// Initializing the label management channels
-	nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
+	localNim := nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
 
 	// This function prevents Kubelet from posting Ready status until CSINode
 	// is both installed and initialized
-	if err := initializeCSINode(host); err != nil {
+	if err := initializeCSINode(host, localNim); err != nil {
 		return errors.New(log("failed to initialize CSINode: %v", err))
 	}
 
+	if _, ok := host.(volume.KubeletVolumeHost); ok {
+		nim = localNim
+	}
+
 	return nil
 }
 
-func initializeCSINode(host volume.VolumeHost) error {
+func initializeCSINode(host volume.VolumeHost, nim nodeinfomanager.Interface) error {
 	kvh, ok := host.(volume.KubeletVolumeHost)
 	if !ok {
 		klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
-- 
2.34.1



================================================
FILE: build-scripts/components/kubernetes/patches/v1.31.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch
================================================
From 55f4864d816c8e7ca0ebb39571dc88dbdf05eff2 Mon Sep 17 00:00:00 2001
From: Angelos Kolaitis <angelos.kolaitis@canonical.com>
Date: Thu, 27 Jul 2023 18:08:00 +0300
Subject: [PATCH] Set log reapply handling to ignore unchanged

---
 staging/src/k8s.io/component-base/logs/api/v1/options.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/staging/src/k8s.io/component-base/logs/api/v1/options.go b/staging/src/k8s.io/component-base/logs/api/v1/options.go
index 2db9b1f5382..e0824dcdc4e 100644
--- a/staging/src/k8s.io/component-base/logs/api/v1/options.go
+++ b/staging/src/k8s.io/component-base/logs/api/v1/options.go
@@ -64,7 +64,7 @@ func NewLoggingConfiguration() *LoggingConfiguration {
 // are no goroutines which might call logging functions. The default for ValidateAndApply
 // and ValidateAndApplyWithOptions is to return an error when called more than once.
 // Binaries and unit tests can override that behavior.
-var ReapplyHandling = ReapplyHandlingError
+var ReapplyHandling = ReapplyHandlingIgnoreUnchanged

 type ReapplyHandlingType int

--
2.34.1


================================================
FILE: build-scripts/components/kubernetes/patches/v1.32.0/0000-Kubelite-integration.patch
================================================
From 819b718ecfee8c4f6fb503d0dea80a43e86cdb6f Mon Sep 17 00:00:00 2001
From: Konstantinos Tsakalozos <kos.tsakalozos@canonical.com>
Date: Wed, 3 Mar 2021 18:19:37 +0200
Subject: [PATCH] Kubelite integration

---
 cmd/kube-apiserver/app/server.go    |  9 ++-
 cmd/kube-scheduler/app/server.go    |  6 +-
 cmd/kubelet/app/server.go           | 13 +++--
 cmd/kubelite/app/daemons/daemon.go  | 85 +++++++++++++++++++++++++++++
 cmd/kubelite/app/options/options.go | 79 +++++++++++++++++++++++++++
 cmd/kubelite/app/server.go          | 80 +++++++++++++++++++++++++++
 cmd/kubelite/kubelite.go            | 25 +++++++++
 pkg/volume/csi/csi_plugin.go        | 10 +++-
 8 files changed, 296 insertions(+), 11 deletions(-)
 create mode 100644 cmd/kubelite/app/daemons/daemon.go
 create mode 100644 cmd/kubelite/app/options/options.go
 create mode 100644 cmd/kubelite/app/server.go
 create mode 100644 cmd/kubelite/kubelite.go

diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go
index 8aa05a4d8f8..75b982aaff9 100644
--- a/cmd/kube-apiserver/app/server.go
+++ b/cmd/kube-apiserver/app/server.go
@@ -63,11 +63,16 @@ func init() {
 }
 
 // NewAPIServerCommand creates a *cobra.Command object with default parameters
-func NewAPIServerCommand() *cobra.Command {
+func NewAPIServerCommand(ctxs ...context.Context) *cobra.Command {
 	_, featureGate := featuregate.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(
 		featuregate.DefaultKubeComponent, utilversion.DefaultBuildEffectiveVersion(), utilfeature.DefaultMutableFeatureGate)
 	s := options.NewServerRunOptions()
-	ctx := genericapiserver.SetupSignalContext()
+	ctx := context.Background()
+	if len(ctxs) == 0 {
+		ctx = genericapiserver.SetupSignalContext()
+	} else {
+		ctx = ctxs[0]
+	}
 
 	cmd := &cobra.Command{
 		Use: "kube-apiserver",
diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go
index 1785bbdcc91..64f01ba5c93 100644
--- a/cmd/kube-scheduler/app/server.go
+++ b/cmd/kube-scheduler/app/server.go
@@ -144,7 +144,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go func() {
-		stopCh := server.SetupSignalHandler()
+                c := cmd.Context()
+                if c == nil {
+                        c = server.SetupSignalContext()
+                }
+                stopCh := c.Done()
 		<-stopCh
 		cancel()
 	}()
diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go
index cfcf6e7d5cd..9c3853173ff 100644
--- a/cmd/kubelet/app/server.go
+++ b/cmd/kubelet/app/server.go
@@ -138,7 +138,7 @@ const (
 )
 
 // NewKubeletCommand creates a *cobra.Command object with default parameters
-func NewKubeletCommand() *cobra.Command {
+func NewKubeletCommand(ctx ...context.Context) *cobra.Command {
 	cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
 	cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
 	kubeletFlags := options.NewKubeletFlags()
@@ -275,6 +275,12 @@ is checked every 20 seconds (also configurable with a flag).`,
 			if err := checkPermissions(); err != nil {
 				klog.ErrorS(err, "kubelet running with insufficient permissions")
 			}
+			runctx := context.Background()
+			if len(ctx) == 0 {
+				runctx = genericapiserver.SetupSignalContext()
+			} else {
+				runctx = ctx[0]
+			}
 
 			// make the kubelet's config safe for logging
 			config := kubeletServer.KubeletConfiguration.DeepCopy()
@@ -284,12 +290,9 @@ is checked every 20 seconds (also configurable with a flag).`,
 			// log the kubelet's config for inspection
 			klog.V(5).InfoS("KubeletConfiguration", "configuration", klog.Format(config))
 
-			// set up signal context for kubelet shutdown
-			ctx := genericapiserver.SetupSignalContext()
-
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
 			// run the kubelet
-			return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
+			return Run(runctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
 		},
 	}
 
diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go
new file mode 100644
index 00000000000..46c1af7fdb9
--- /dev/null
+++ b/cmd/kubelite/app/daemons/daemon.go
@@ -0,0 +1,85 @@
+package daemon
+
+import (
+	"context"
+
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/clientcmd"
+	genericcontrollermanager "k8s.io/controller-manager/app"
+	"k8s.io/klog/v2"
+	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
+	controller "k8s.io/kubernetes/cmd/kube-controller-manager/app"
+	proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
+	scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
+	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
+
+	"time"
+)
+
+func StartControllerManager(args []string, ctx context.Context) {
+	command := controller.NewControllerManagerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Controller Manager")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Controller Manager exited %v", err)
+	}
+	klog.Info("Stopping Controller Manager")
+}
+
+func StartScheduler(args []string, ctx context.Context) {
+	command := scheduler.NewSchedulerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Scheduler")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Scheduler exited %v", err)
+	}
+	klog.Info("Stopping Scheduler")
+}
+
+func StartProxy(args []string) {
+	command := proxy.NewProxyCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Proxy")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Proxy exited %v", err)
+	}
+	klog.Info("Stopping Proxy")
+}
+
+func StartKubelet(args []string, ctx context.Context) {
+	command := kubelet.NewKubeletCommand(ctx)
+	command.SetArgs(args)
+
+	klog.Info("Starting Kubelet")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Kubelet exited %v", err)
+	}
+	klog.Info("Stopping Kubelet")
+}
+
+func StartAPIServer(args []string, ctx context.Context) {
+	command := apiserver.NewAPIServerCommand(ctx)
+	command.SetArgs(args)
+	klog.Info("Starting API Server")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("API Server exited %v", err)
+	}
+	klog.Info("Stopping API Server")
+}
+
+func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) {
+	klog.Info("Waiting for the API server")
+	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath)
+	if err != nil {
+		klog.Fatalf("could not find the cluster's kubeconfig file %v", err)
+	}
+	// create the client
+	client, err := kubernetes.NewForConfig(config)
+	if err != nil {
+		klog.Fatalf("could not create client to the cluster %v", err)
+	}
+	genericcontrollermanager.WaitForAPIServer(client, timeout)
+}
diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go
new file mode 100644
index 00000000000..80f1d8b09fc
--- /dev/null
+++ b/cmd/kubelite/app/options/options.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package options
+
+import (
+	"bufio"
+	"k8s.io/klog/v2"
+	"os"
+	"strings"
+)
+
+// Options has all the params needed to run a Kubelite
+type Options struct {
+	SchedulerArgsFile         string
+	ControllerManagerArgsFile string
+	ProxyArgsFile             string
+	KubeletArgsFile           string
+	APIServerArgsFile         string
+	KubeconfigFile    		  string
+	StartControlPlane		  bool
+}
+
+func NewOptions() (*Options){
+	o := Options{
+		"/var/snap/microk8s/current/args/kube-scheduler",
+		"/var/snap/microk8s/current/args/kube-controller-manager",
+		"/var/snap/microk8s/current/args/kube-proxy",
+		"/var/snap/microk8s/current/args/kubelet",
+		"/var/snap/microk8s/current/args/kube-apiserver",
+		"/var/snap/microk8s/current/credentials/client.config",
+		true,
+	}
+	return &o
+}
+
+func ReadArgsFromFile(filename string) []string {
+	var args []string
+	file, err := os.Open(filename)
+	if err != nil {
+		klog.Fatalf("Failed to open arguments file %v", err)
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		line = strings.TrimSpace(line)
+		// ignore lines with # and empty lines
+		if len(line) <= 0 || strings.HasPrefix(line, "#") {
+			continue
+		}
+		// remove " and '
+		for _, r := range "\"'" {
+			line = strings.ReplaceAll(line, string(r), "")
+		}
+		for _, part := range strings.Split(line, " ") {
+
+			args = append(args, os.ExpandEnv(part))
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		klog.Fatalf("Failed to read arguments file %v", err)
+	}
+	return args
+}
diff --git a/cmd/kubelite/app/server.go b/cmd/kubelite/app/server.go
new file mode 100644
index 00000000000..4ff36cd6432
--- /dev/null
+++ b/cmd/kubelite/app/server.go
@@ -0,0 +1,80 @@
+/*
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package app
+
+import (
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/spf13/cobra"
+	genericapiserver "k8s.io/apiserver/pkg/server"
+	daemon "k8s.io/kubernetes/cmd/kubelite/app/daemons"
+	"k8s.io/kubernetes/cmd/kubelite/app/options"
+)
+
+var opts = options.NewOptions()
+
+// liteCmd represents the base command when called without any subcommands
+var liteCmd = &cobra.Command{
+	Use:   "kubelite",
+	Short: "Single server kubernetes",
+	Long:  `A single server that spawns all other kubernetes servers as threads`,
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	Run: func(cmd *cobra.Command, args []string) {
+		ctx := genericapiserver.SetupSignalContext()
+
+		if opts.StartControlPlane {
+			apiserverArgs := options.ReadArgsFromFile(opts.APIServerArgsFile)
+			go daemon.StartAPIServer(apiserverArgs, ctx)
+			daemon.WaitForAPIServer(opts.KubeconfigFile, 360*time.Second)
+
+			controllerArgs := options.ReadArgsFromFile(opts.ControllerManagerArgsFile)
+			go daemon.StartControllerManager(controllerArgs, ctx)
+
+			schedulerArgs := options.ReadArgsFromFile(opts.SchedulerArgsFile)
+			go daemon.StartScheduler(schedulerArgs, ctx)
+		}
+
+		proxyArgs := options.ReadArgsFromFile(opts.ProxyArgsFile)
+		go daemon.StartProxy(proxyArgs)
+
+		kubeletArgs := options.ReadArgsFromFile(opts.KubeletArgsFile)
+		daemon.StartKubelet(kubeletArgs, ctx)
+	},
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the liteCmd.
+func Execute() {
+	if err := liteCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func init() {
+	cobra.OnInitialize()
+
+	liteCmd.Flags().StringVar(&opts.SchedulerArgsFile, "scheduler-args-file", opts.SchedulerArgsFile, "file with the arguments for the scheduler")
+	liteCmd.Flags().StringVar(&opts.ControllerManagerArgsFile, "controller-manager-args-file", opts.ControllerManagerArgsFile, "file with the arguments for the controller manager")
+	liteCmd.Flags().StringVar(&opts.ProxyArgsFile, "proxy-args-file", opts.ProxyArgsFile, "file with the arguments for kube-proxy")
+	liteCmd.Flags().StringVar(&opts.KubeletArgsFile, "kubelet-args-file", opts.KubeletArgsFile, "file with the arguments for kubelet")
+	liteCmd.Flags().StringVar(&opts.APIServerArgsFile, "apiserver-args-file", opts.APIServerArgsFile, "file with the arguments for the API server")
+	liteCmd.Flags().StringVar(&opts.KubeconfigFile, "kubeconfig-file", opts.KubeconfigFile, "the kubeconfig file to use to healthcheck the API server")
+	liteCmd.Flags().BoolVar(&opts.StartControlPlane, "start-control-plane", opts.StartControlPlane, "start the control plane (API server, scheduler and controller manager)")
+}
diff --git a/cmd/kubelite/kubelite.go b/cmd/kubelite/kubelite.go
new file mode 100644
index 00000000000..30ab604f480
--- /dev/null
+++ b/cmd/kubelite/kubelite.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+	"github.com/spf13/pflag"
+	cliflag "k8s.io/component-base/cli/flag"
+
+	"k8s.io/component-base/logs"
+	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin
+	_ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
+	"k8s.io/kubernetes/cmd/kubelite/app"
+)
+
+func main() {
+	println("Starting kubelite")
+	// TODO: once we switch everything over to Cobra commands, we can go back to calling
+	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
+	// normalize func and add the go flag set by hand.
+	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
+	// utilflag.InitFlags()
+	logs.InitLogs()
+	defer logs.FlushLogs()
+
+	app.Execute()
+	println("Stopping kubelite")
+}
diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go
index 59fa6245b7f..6443dffd695 100644
--- a/pkg/volume/csi/csi_plugin.go
+++ b/pkg/volume/csi/csi_plugin.go
@@ -256,18 +256,22 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
 	}
 
 	// Initializing the label management channels
-	nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
+	localNim := nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
 
 	// This function prevents Kubelet from posting Ready status until CSINode
 	// is both installed and initialized
-	if err := initializeCSINode(host); err != nil {
+	if err := initializeCSINode(host, localNim); err != nil {
 		return errors.New(log("failed to initialize CSINode: %v", err))
 	}
 
+	if _, ok := host.(volume.KubeletVolumeHost); ok {
+		nim = localNim
+	}
+
 	return nil
 }
 
-func initializeCSINode(host volume.VolumeHost) error {
+func initializeCSINode(host volume.VolumeHost, nim nodeinfomanager.Interface) error {
 	kvh, ok := host.(volume.KubeletVolumeHost)
 	if !ok {
 		klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
-- 
2.43.0



================================================
FILE: build-scripts/components/kubernetes/patches/v1.32.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch
================================================
From 55f4864d816c8e7ca0ebb39571dc88dbdf05eff2 Mon Sep 17 00:00:00 2001
From: Angelos Kolaitis <angelos.kolaitis@canonical.com>
Date: Thu, 27 Jul 2023 18:08:00 +0300
Subject: [PATCH] Set log reapply handling to ignore unchanged

---
 staging/src/k8s.io/component-base/logs/api/v1/options.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/staging/src/k8s.io/component-base/logs/api/v1/options.go b/staging/src/k8s.io/component-base/logs/api/v1/options.go
index 2db9b1f5382..e0824dcdc4e 100644
--- a/staging/src/k8s.io/component-base/logs/api/v1/options.go
+++ b/staging/src/k8s.io/component-base/logs/api/v1/options.go
@@ -64,7 +64,7 @@ func NewLoggingConfiguration() *LoggingConfiguration {
 // are no goroutines which might call logging functions. The default for ValidateAndApply
 // and ValidateAndApplyWithOptions is to return an error when called more than once.
 // Binaries and unit tests can override that behavior.
-var ReapplyHandling = ReapplyHandlingError
+var ReapplyHandling = ReapplyHandlingIgnoreUnchanged

 type ReapplyHandlingType int

--
2.34.1


================================================
FILE: build-scripts/components/kubernetes/patches/v1.33.0/0000-Kubelite-integration.patch
================================================
From aa3c3a427082e2a1ddd9f72790a8977efefee1cf Mon Sep 17 00:00:00 2001
From: Konstantinos Tsakalozos <kos.tsakalozos@canonical.com>
Date: Wed, 3 Mar 2021 18:19:37 +0200
Subject: [PATCH 1/2] Kubelite integration

---
 cmd/kube-apiserver/app/server.go    |  9 ++-
 cmd/kube-scheduler/app/server.go    |  6 +-
 cmd/kubelet/app/server.go           | 13 +++--
 cmd/kubelite/app/daemons/daemon.go  | 85 +++++++++++++++++++++++++++++
 cmd/kubelite/app/options/options.go | 79 +++++++++++++++++++++++++++
 cmd/kubelite/app/server.go          | 80 +++++++++++++++++++++++++++
 cmd/kubelite/kubelite.go            | 25 +++++++++
 pkg/volume/csi/csi_plugin.go        | 11 +++-
 8 files changed, 297 insertions(+), 11 deletions(-)
 create mode 100644 cmd/kubelite/app/daemons/daemon.go
 create mode 100644 cmd/kubelite/app/options/options.go
 create mode 100644 cmd/kubelite/app/server.go
 create mode 100644 cmd/kubelite/kubelite.go

diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go
index 042ddc9714a..6a6d4b07f40 100644
--- a/cmd/kube-apiserver/app/server.go
+++ b/cmd/kube-apiserver/app/server.go
@@ -65,9 +65,14 @@ func init() {
 }
 
 // NewAPIServerCommand creates a *cobra.Command object with default parameters
-func NewAPIServerCommand() *cobra.Command {
+func NewAPIServerCommand(ctxs ...context.Context) *cobra.Command {
 	s := options.NewServerRunOptions()
-	ctx := genericapiserver.SetupSignalContext()
+	ctx := context.Background()
+	if len(ctxs) == 0 {
+		ctx = genericapiserver.SetupSignalContext()
+	} else {
+		ctx = ctxs[0]
+	}
 	featureGate := s.GenericServerRunOptions.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent)
 
 	cmd := &cobra.Command{
diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go
index c9ab27027cf..aade3f81dc4 100644
--- a/cmd/kube-scheduler/app/server.go
+++ b/cmd/kube-scheduler/app/server.go
@@ -149,7 +149,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go func() {
-		stopCh := server.SetupSignalHandler()
+                c := cmd.Context()
+                if c == nil {
+                        c = server.SetupSignalContext()
+                }
+                stopCh := c.Done()
 		<-stopCh
 		cancel()
 	}()
diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go
index 3bd3ac16eb7..70fa7fd86b7 100644
--- a/cmd/kubelet/app/server.go
+++ b/cmd/kubelet/app/server.go
@@ -135,7 +135,7 @@ func init() {
 }
 
 // NewKubeletCommand creates a *cobra.Command object with default parameters
-func NewKubeletCommand() *cobra.Command {
+func NewKubeletCommand(ctx ...context.Context) *cobra.Command {
 	cleanFlagSet := pflag.NewFlagSet(server.ComponentKubelet, pflag.ContinueOnError)
 	cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
 	kubeletFlags := options.NewKubeletFlags()
@@ -279,6 +279,12 @@ is checked every 20 seconds (also configurable with a flag).`,
 			if err := checkPermissions(); err != nil {
 				klog.ErrorS(err, "kubelet running with insufficient permissions")
 			}
+			runctx := context.Background()
+			if len(ctx) == 0 {
+				runctx = genericapiserver.SetupSignalContext()
+			} else {
+				runctx = ctx[0]
+			}
 
 			// make the kubelet's config safe for logging
 			config := kubeletServer.KubeletConfiguration.DeepCopy()
@@ -288,12 +294,9 @@ is checked every 20 seconds (also configurable with a flag).`,
 			// log the kubelet's config for inspection
 			klog.V(5).InfoS("KubeletConfiguration", "configuration", klog.Format(config))
 
-			// set up signal context for kubelet shutdown
-			ctx := genericapiserver.SetupSignalContext()
-
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
 			// run the kubelet
-			return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
+			return Run(runctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
 		},
 	}
 
diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go
new file mode 100644
index 00000000000..46c1af7fdb9
--- /dev/null
+++ b/cmd/kubelite/app/daemons/daemon.go
@@ -0,0 +1,85 @@
+package daemon
+
+import (
+	"context"
+
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/clientcmd"
+	genericcontrollermanager "k8s.io/controller-manager/app"
+	"k8s.io/klog/v2"
+	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
+	controller "k8s.io/kubernetes/cmd/kube-controller-manager/app"
+	proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
+	scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
+	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
+
+	"time"
+)
+
+func StartControllerManager(args []string, ctx context.Context) {
+	command := controller.NewControllerManagerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Controller Manager")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Controller Manager exited %v", err)
+	}
+	klog.Info("Stopping Controller Manager")
+}
+
+func StartScheduler(args []string, ctx context.Context) {
+	command := scheduler.NewSchedulerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Scheduler")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Scheduler exited %v", err)
+	}
+	klog.Info("Stopping Scheduler")
+}
+
+func StartProxy(args []string) {
+	command := proxy.NewProxyCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Proxy")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Proxy exited %v", err)
+	}
+	klog.Info("Stopping Proxy")
+}
+
+func StartKubelet(args []string, ctx context.Context) {
+	command := kubelet.NewKubeletCommand(ctx)
+	command.SetArgs(args)
+
+	klog.Info("Starting Kubelet")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Kubelet exited %v", err)
+	}
+	klog.Info("Stopping Kubelet")
+}
+
+func StartAPIServer(args []string, ctx context.Context) {
+	command := apiserver.NewAPIServerCommand(ctx)
+	command.SetArgs(args)
+	klog.Info("Starting API Server")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("API Server exited %v", err)
+	}
+	klog.Info("Stopping API Server")
+}
+
+func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) {
+	klog.Info("Waiting for the API server")
+	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath)
+	if err != nil {
+		klog.Fatalf("could not find the cluster's kubeconfig file %v", err)
+	}
+	// create the client
+	client, err := kubernetes.NewForConfig(config)
+	if err != nil {
+		klog.Fatalf("could not create client to the cluster %v", err)
+	}
+	genericcontrollermanager.WaitForAPIServer(client, timeout)
+}
diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go
new file mode 100644
index 00000000000..80f1d8b09fc
--- /dev/null
+++ b/cmd/kubelite/app/options/options.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package options
+
+import (
+	"bufio"
+	"k8s.io/klog/v2"
+	"os"
+	"strings"
+)
+
+// Options has all the params needed to run a Kubelite
+type Options struct {
+	SchedulerArgsFile         string
+	ControllerManagerArgsFile string
+	ProxyArgsFile             string
+	KubeletArgsFile           string
+	APIServerArgsFile         string
+	KubeconfigFile    		  string
+	StartControlPlane		  bool
+}
+
+func NewOptions() (*Options){
+	o := Options{
+		"/var/snap/microk8s/current/args/kube-scheduler",
+		"/var/snap/microk8s/current/args/kube-controller-manager",
+		"/var/snap/microk8s/current/args/kube-proxy",
+		"/var/snap/microk8s/current/args/kubelet",
+		"/var/snap/microk8s/current/args/kube-apiserver",
+		"/var/snap/microk8s/current/credentials/client.config",
+		true,
+	}
+	return &o
+}
+
+func ReadArgsFromFile(filename string) []string {
+	var args []string
+	file, err := os.Open(filename)
+	if err != nil {
+		klog.Fatalf("Failed to open arguments file %v", err)
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		line = strings.TrimSpace(line)
+		// ignore lines with # and empty lines
+		if len(line) <= 0 || strings.HasPrefix(line, "#") {
+			continue
+		}
+		// remove " and '
+		for _, r := range "\"'" {
+			line = strings.ReplaceAll(line, string(r), "")
+		}
+		for _, part := range strings.Split(line, " ") {
+
+			args = append(args, os.ExpandEnv(part))
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		klog.Fatalf("Failed to read arguments file %v", err)
+	}
+	return args
+}
diff --git a/cmd/kubelite/app/server.go b/cmd/kubelite/app/server.go
new file mode 100644
index 00000000000..4ff36cd6432
--- /dev/null
+++ b/cmd/kubelite/app/server.go
@@ -0,0 +1,80 @@
+/*
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package app
+
+import (
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/spf13/cobra"
+	genericapiserver "k8s.io/apiserver/pkg/server"
+	daemon "k8s.io/kubernetes/cmd/kubelite/app/daemons"
+	"k8s.io/kubernetes/cmd/kubelite/app/options"
+)
+
+var opts = options.NewOptions()
+
+// liteCmd represents the base command when called without any subcommands
+var liteCmd = &cobra.Command{
+	Use:   "kubelite",
+	Short: "Single server kubernetes",
+	Long:  `A single server that spawns all other kubernetes servers as threads`,
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	Run: func(cmd *cobra.Command, args []string) {
+		ctx := genericapiserver.SetupSignalContext()
+
+		if opts.StartControlPlane {
+			apiserverArgs := options.ReadArgsFromFile(opts.APIServerArgsFile)
+			go daemon.StartAPIServer(apiserverArgs, ctx)
+			daemon.WaitForAPIServer(opts.KubeconfigFile, 360*time.Second)
+
+			controllerArgs := options.ReadArgsFromFile(opts.ControllerManagerArgsFile)
+			go daemon.StartControllerManager(controllerArgs, ctx)
+
+			schedulerArgs := options.ReadArgsFromFile(opts.SchedulerArgsFile)
+			go daemon.StartScheduler(schedulerArgs, ctx)
+		}
+
+		proxyArgs := options.ReadArgsFromFile(opts.ProxyArgsFile)
+		go daemon.StartProxy(proxyArgs)
+
+		kubeletArgs := options.ReadArgsFromFile(opts.KubeletArgsFile)
+		daemon.StartKubelet(kubeletArgs, ctx)
+	},
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the liteCmd.
+func Execute() {
+	if err := liteCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func init() {
+	cobra.OnInitialize()
+
+	liteCmd.Flags().StringVar(&opts.SchedulerArgsFile, "scheduler-args-file", opts.SchedulerArgsFile, "file with the arguments for the scheduler")
+	liteCmd.Flags().StringVar(&opts.ControllerManagerArgsFile, "controller-manager-args-file", opts.ControllerManagerArgsFile, "file with the arguments for the controller manager")
+	liteCmd.Flags().StringVar(&opts.ProxyArgsFile, "proxy-args-file", opts.ProxyArgsFile, "file with the arguments for kube-proxy")
+	liteCmd.Flags().StringVar(&opts.KubeletArgsFile, "kubelet-args-file", opts.KubeletArgsFile, "file with the arguments for kubelet")
+	liteCmd.Flags().StringVar(&opts.APIServerArgsFile, "apiserver-args-file", opts.APIServerArgsFile, "file with the arguments for the API server")
+	liteCmd.Flags().StringVar(&opts.KubeconfigFile, "kubeconfig-file", opts.KubeconfigFile, "the kubeconfig file to use to healthcheck the API server")
+	liteCmd.Flags().BoolVar(&opts.StartControlPlane, "start-control-plane", opts.StartControlPlane, "start the control plane (API server, scheduler and controller manager)")
+}
diff --git a/cmd/kubelite/kubelite.go b/cmd/kubelite/kubelite.go
new file mode 100644
index 00000000000..30ab604f480
--- /dev/null
+++ b/cmd/kubelite/kubelite.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+	"github.com/spf13/pflag"
+	cliflag "k8s.io/component-base/cli/flag"
+
+	"k8s.io/component-base/logs"
+	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin
+	_ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
+	"k8s.io/kubernetes/cmd/kubelite/app"
+)
+
+func main() {
+	println("Starting kubelite")
+	// TODO: once we switch everything over to Cobra commands, we can go back to calling
+	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
+	// normalize func and add the go flag set by hand.
+	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
+	// utilflag.InitFlags()
+	logs.InitLogs()
+	defer logs.FlushLogs()
+
+	app.Execute()
+	println("Stopping kubelite")
+}
diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go
index 902f31e9911..95d20ba48d8 100644
--- a/pkg/volume/csi/csi_plugin.go
+++ b/pkg/volume/csi/csi_plugin.go
@@ -345,18 +345,23 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
 	}
 
 	// Initializing the label management channels
-	nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
+	localNim := nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
 	PluginHandler.csiPlugin = p
 
 	// This function prevents Kubelet from posting Ready status until CSINode
 	// is both installed and initialized
-	if err := initializeCSINode(host, p.csiDriverInformer); err != nil {
+	if err := initializeCSINode(host, p.csiDriverInformer, localNim); err != nil {
 		return errors.New(log("failed to initialize CSINode: %v", err))
 	}
+
+	if _, ok := host.(volume.KubeletVolumeHost); ok {
+		nim = localNim
+	}
+
 	return nil
 }
 
-func initializeCSINode(host volume.VolumeHost, csiDriverInformer cache.SharedIndexInformer) error {
+func initializeCSINode(host volume.VolumeHost, csiDriverInformer cache.SharedIndexInformer, nim nodeinfomanager.Interface) error {
 	kvh, ok := host.(volume.KubeletVolumeHost)
 	if !ok {
 		klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
-- 
2.49.0



================================================
FILE: build-scripts/components/kubernetes/patches/v1.33.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch
================================================
From beaeb73228b7e4a836b3bd5d73e49402279a47a6 Mon Sep 17 00:00:00 2001
From: Angelos Kolaitis <angelos.kolaitis@canonical.com>
Date: Thu, 27 Jul 2023 18:08:00 +0300
Subject: [PATCH 2/2] Set log reapply handling to ignore unchanged

---
 staging/src/k8s.io/component-base/logs/api/v1/options.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/staging/src/k8s.io/component-base/logs/api/v1/options.go b/staging/src/k8s.io/component-base/logs/api/v1/options.go
index 95c0a2cba98..4482564ad95 100644
--- a/staging/src/k8s.io/component-base/logs/api/v1/options.go
+++ b/staging/src/k8s.io/component-base/logs/api/v1/options.go
@@ -65,7 +65,7 @@ func NewLoggingConfiguration() *LoggingConfiguration {
 // are no goroutines which might call logging functions. The default for ValidateAndApply
 // and ValidateAndApplyWithOptions is to return an error when called more than once.
 // Binaries and unit tests can override that behavior.
-var ReapplyHandling = ReapplyHandlingError
+var ReapplyHandling = ReapplyHandlingIgnoreUnchanged
 
 type ReapplyHandlingType int
 
-- 
2.49.0



================================================
FILE: build-scripts/components/kubernetes/patches/v1.34.0/0000-Kubelite-integration.patch
================================================
From 241fc2a00be6fde3f7059ae61842cba44dff82a5 Mon Sep 17 00:00:00 2001
From: Konstantinos Tsakalozos <kos.tsakalozos@canonical.com>
Date: Wed, 3 Mar 2021 18:19:37 +0200
Subject: [PATCH] Kubelite integration

---
 cmd/kube-apiserver/app/server.go              |  9 +-
 .../app/options/options.go                    | 10 --
 cmd/kube-scheduler/app/server.go              |  6 +-
 cmd/kubelet/app/server.go                     |  4 -
 cmd/kubelite/app/daemons/daemon.go            | 85 +++++++++++++++++
 cmd/kubelite/app/options/options.go           | 79 ++++++++++++++++
 cmd/kubelite/app/server.go                    | 91 +++++++++++++++++++
 cmd/kubelite/kubelite.go                      | 25 +++++
 pkg/volume/csi/csi_plugin.go                  | 11 ++-
 9 files changed, 300 insertions(+), 20 deletions(-)
 create mode 100644 cmd/kubelite/app/daemons/daemon.go
 create mode 100644 cmd/kubelite/app/options/options.go
 create mode 100644 cmd/kubelite/app/server.go
 create mode 100644 cmd/kubelite/kubelite.go

diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go
index 71ebb317461..86dc50ce671 100644
--- a/cmd/kube-apiserver/app/server.go
+++ b/cmd/kube-apiserver/app/server.go
@@ -67,9 +67,14 @@ func init() {
 }
 
 // NewAPIServerCommand creates a *cobra.Command object with default parameters
-func NewAPIServerCommand() *cobra.Command {
+func NewAPIServerCommand(ctxs ...context.Context) *cobra.Command {
 	s := options.NewServerRunOptions()
-	ctx := genericapiserver.SetupSignalContext()
+	ctx := context.Background()
+	if len(ctxs) == 0 {
+		ctx = genericapiserver.SetupSignalContext()
+	} else {
+		ctx = ctxs[0]
+	}
 	featureGate := s.GenericServerRunOptions.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent)
 
 	cmd := &cobra.Command{
diff --git a/cmd/kube-controller-manager/app/options/options.go b/cmd/kube-controller-manager/app/options/options.go
index 176b2a14bc1..5048b04014e 100644
--- a/cmd/kube-controller-manager/app/options/options.go
+++ b/cmd/kube-controller-manager/app/options/options.go
@@ -25,11 +25,9 @@ import (
 	v1 "k8s.io/api/core/v1"
 	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
-	"k8s.io/apimachinery/pkg/util/version"
 	apiserveroptions "k8s.io/apiserver/pkg/server/options"
 	"k8s.io/apiserver/pkg/util/compatibility"
 	utilfeature "k8s.io/apiserver/pkg/util/feature"
-	clientgofeaturegate "k8s.io/client-go/features"
 	clientset "k8s.io/client-go/kubernetes"
 	clientgokubescheme "k8s.io/client-go/kubernetes/scheme"
 	restclient "k8s.io/client-go/rest"
@@ -40,7 +38,6 @@ import (
 	cpoptions "k8s.io/cloud-provider/options"
 	cliflag "k8s.io/component-base/cli/flag"
 	basecompatibility "k8s.io/component-base/compatibility"
-	"k8s.io/component-base/featuregate"
 	"k8s.io/component-base/logs"
 	logsapi "k8s.io/component-base/logs/api/v1"
 	"k8s.io/component-base/metrics"
@@ -298,13 +295,6 @@ func (s *KubeControllerManagerOptions) Flags(allControllers []string, disabledBy
 	fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig).")
 	fs.StringVar(&s.Generic.ClientConnection.Kubeconfig, "kubeconfig", s.Generic.ClientConnection.Kubeconfig, "Path to kubeconfig file with authorization and master location information (the master location can be overridden by the master flag).")
 
-	if !utilfeature.DefaultFeatureGate.Enabled(featuregate.Feature(clientgofeaturegate.WatchListClient)) {
-		ver := version.MustParse("1.34")
-		if err := utilfeature.DefaultMutableFeatureGate.OverrideDefaultAtVersion(featuregate.Feature(clientgofeaturegate.WatchListClient), true, ver); err != nil {
-			panic(fmt.Sprintf("unable to set %s feature gate, err: %v", clientgofeaturegate.WatchListClient, err))
-		}
-	}
-
 	s.ComponentGlobalsRegistry.AddFlags(fss.FlagSet("generic"))
 
 	return fss
diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go
index 803e0c37861..5b58d437d30 100644
--- a/cmd/kube-scheduler/app/server.go
+++ b/cmd/kube-scheduler/app/server.go
@@ -150,7 +150,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go func() {
-		stopCh := server.SetupSignalHandler()
+                c := cmd.Context()
+                if c == nil {
+                        c = server.SetupSignalContext()
+                }
+                stopCh := c.Done()
 		<-stopCh
 		cancel()
 	}()
diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go
index f069f6b08b9..62f3ca58dc7 100644
--- a/cmd/kubelet/app/server.go
+++ b/cmd/kubelet/app/server.go
@@ -63,7 +63,6 @@ import (
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/apimachinery/pkg/util/validation/field"
 	"k8s.io/apimachinery/pkg/util/wait"
-	genericapiserver "k8s.io/apiserver/pkg/server"
 	"k8s.io/apiserver/pkg/server/healthz"
 	utilfeature "k8s.io/apiserver/pkg/util/feature"
 	clientset "k8s.io/client-go/kubernetes"
@@ -291,9 +290,6 @@ is checked every 20 seconds (also configurable with a flag).`,
 			// log the kubelet's config for inspection
 			logger.V(5).Info("KubeletConfiguration", "configuration", klog.Format(config))
 
-			// set up signal context for kubelet shutdown
-			ctx := genericapiserver.SetupSignalContext()
-
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
 			// run the kubelet
 			return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go
new file mode 100644
index 00000000000..46c1af7fdb9
--- /dev/null
+++ b/cmd/kubelite/app/daemons/daemon.go
@@ -0,0 +1,85 @@
+package daemon
+
+import (
+	"context"
+
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/clientcmd"
+	genericcontrollermanager "k8s.io/controller-manager/app"
+	"k8s.io/klog/v2"
+	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
+	controller "k8s.io/kubernetes/cmd/kube-controller-manager/app"
+	proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
+	scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
+	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
+
+	"time"
+)
+
+func StartControllerManager(args []string, ctx context.Context) {
+	command := controller.NewControllerManagerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Controller Manager")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Controller Manager exited %v", err)
+	}
+	klog.Info("Stopping Controller Manager")
+}
+
+func StartScheduler(args []string, ctx context.Context) {
+	command := scheduler.NewSchedulerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Scheduler")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Scheduler exited %v", err)
+	}
+	klog.Info("Stopping Scheduler")
+}
+
+func StartProxy(args []string) {
+	command := proxy.NewProxyCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Proxy")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Proxy exited %v", err)
+	}
+	klog.Info("Stopping Proxy")
+}
+
+func StartKubelet(args []string, ctx context.Context) {
+	command := kubelet.NewKubeletCommand(ctx)
+	command.SetArgs(args)
+
+	klog.Info("Starting Kubelet")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Kubelet exited %v", err)
+	}
+	klog.Info("Stopping Kubelet")
+}
+
+func StartAPIServer(args []string, ctx context.Context) {
+	command := apiserver.NewAPIServerCommand(ctx)
+	command.SetArgs(args)
+	klog.Info("Starting API Server")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("API Server exited %v", err)
+	}
+	klog.Info("Stopping API Server")
+}
+
+func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) {
+	klog.Info("Waiting for the API server")
+	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath)
+	if err != nil {
+		klog.Fatalf("could not find the cluster's kubeconfig file %v", err)
+	}
+	// create the client
+	client, err := kubernetes.NewForConfig(config)
+	if err != nil {
+		klog.Fatalf("could not create client to the cluster %v", err)
+	}
+	genericcontrollermanager.WaitForAPIServer(client, timeout)
+}
diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go
new file mode 100644
index 00000000000..80f1d8b09fc
--- /dev/null
+++ b/cmd/kubelite/app/options/options.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package options
+
+import (
+	"bufio"
+	"k8s.io/klog/v2"
+	"os"
+	"strings"
+)
+
+// Options has all the params needed to run a Kubelite
+type Options struct {
+	SchedulerArgsFile         string
+	ControllerManagerArgsFile string
+	ProxyArgsFile             string
+	KubeletArgsFile           string
+	APIServerArgsFile         string
+	KubeconfigFile    		  string
+	StartControlPlane		  bool
+}
+
+func NewOptions() (*Options){
+	o := Options{
+		"/var/snap/microk8s/current/args/kube-scheduler",
+		"/var/snap/microk8s/current/args/kube-controller-manager",
+		"/var/snap/microk8s/current/args/kube-proxy",
+		"/var/snap/microk8s/current/args/kubelet",
+		"/var/snap/microk8s/current/args/kube-apiserver",
+		"/var/snap/microk8s/current/credentials/client.config",
+		true,
+	}
+	return &o
+}
+
+func ReadArgsFromFile(filename string) []string {
+	var args []string
+	file, err := os.Open(filename)
+	if err != nil {
+		klog.Fatalf("Failed to open arguments file %v", err)
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		line = strings.TrimSpace(line)
+		// ignore lines with # and empty lines
+		if len(line) <= 0 || strings.HasPrefix(line, "#") {
+			continue
+		}
+		// remove " and '
+		for _, r := range "\"'" {
+			line = strings.ReplaceAll(line, string(r), "")
+		}
+		for _, part := range strings.Split(line, " ") {
+
+			args = append(args, os.ExpandEnv(part))
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		klog.Fatalf("Failed to read arguments file %v", err)
+	}
+	return args
+}
diff --git a/cmd/kubelite/app/server.go b/cmd/kubelite/app/server.go
new file mode 100644
index 00000000000..858a7c1094c
--- /dev/null
+++ b/cmd/kubelite/app/server.go
@@ -0,0 +1,91 @@
+/*
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package app
+
+import (
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/spf13/cobra"
+	"k8s.io/apimachinery/pkg/util/version"
+	genericapiserver "k8s.io/apiserver/pkg/server"
+	utilfeature "k8s.io/apiserver/pkg/util/feature"
+	clientgofeaturegate "k8s.io/client-go/features"
+	"k8s.io/component-base/featuregate"
+	daemon "k8s.io/kubernetes/cmd/kubelite/app/daemons"
+	"k8s.io/kubernetes/cmd/kubelite/app/options"
+)
+
+var opts = options.NewOptions()
+
+// liteCmd represents the base command when called without any subcommands
+var liteCmd = &cobra.Command{
+	Use:   "kubelite",
+	Short: "Single server kubernetes",
+	Long:  `A single server that spawns all other kubernetes servers as threads`,
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	Run: func(cmd *cobra.Command, args []string) {
+		ctx := genericapiserver.SetupSignalContext()
+
+		if opts.StartControlPlane {
+			if !utilfeature.DefaultFeatureGate.Enabled(featuregate.Feature(clientgofeaturegate.WatchListClient)) {
+				ver := version.MustParse("1.34")
+				if err := utilfeature.DefaultMutableFeatureGate.OverrideDefaultAtVersion(featuregate.Feature(clientgofeaturegate.WatchListClient), true, ver); err != nil {
+					panic(fmt.Sprintf("unable to set %s feature gate, err: %v", clientgofeaturegate.WatchListClient, err))
+				}
+			}
+
+			apiserverArgs := options.ReadArgsFromFile(opts.APIServerArgsFile)
+			go daemon.StartAPIServer(apiserverArgs, ctx)
+			daemon.WaitForAPIServer(opts.KubeconfigFile, 360*time.Second)
+
+			controllerArgs := options.ReadArgsFromFile(opts.ControllerManagerArgsFile)
+			go daemon.StartControllerManager(controllerArgs, ctx)
+
+			schedulerArgs := options.ReadArgsFromFile(opts.SchedulerArgsFile)
+			go daemon.StartScheduler(schedulerArgs, ctx)
+		}
+
+		proxyArgs := options.ReadArgsFromFile(opts.ProxyArgsFile)
+		go daemon.StartProxy(proxyArgs)
+
+		kubeletArgs := options.ReadArgsFromFile(opts.KubeletArgsFile)
+		daemon.StartKubelet(kubeletArgs, ctx)
+	},
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the liteCmd.
+func Execute() {
+	if err := liteCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func init() {
+	cobra.OnInitialize()
+
+	liteCmd.Flags().StringVar(&opts.SchedulerArgsFile, "scheduler-args-file", opts.SchedulerArgsFile, "file with the arguments for the scheduler")
+	liteCmd.Flags().StringVar(&opts.ControllerManagerArgsFile, "controller-manager-args-file", opts.ControllerManagerArgsFile, "file with the arguments for the controller manager")
+	liteCmd.Flags().StringVar(&opts.ProxyArgsFile, "proxy-args-file", opts.ProxyArgsFile, "file with the arguments for kube-proxy")
+	liteCmd.Flags().StringVar(&opts.KubeletArgsFile, "kubelet-args-file", opts.KubeletArgsFile, "file with the arguments for kubelet")
+	liteCmd.Flags().StringVar(&opts.APIServerArgsFile, "apiserver-args-file", opts.APIServerArgsFile, "file with the arguments for the API server")
+	liteCmd.Flags().StringVar(&opts.KubeconfigFile, "kubeconfig-file", opts.KubeconfigFile, "the kubeconfig file to use to healthcheck the API server")
+	liteCmd.Flags().BoolVar(&opts.StartControlPlane, "start-control-plane", opts.StartControlPlane, "start the control plane (API server, scheduler and controller manager)")
+}
diff --git a/cmd/kubelite/kubelite.go b/cmd/kubelite/kubelite.go
new file mode 100644
index 00000000000..30ab604f480
--- /dev/null
+++ b/cmd/kubelite/kubelite.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+	"github.com/spf13/pflag"
+	cliflag "k8s.io/component-base/cli/flag"
+
+	"k8s.io/component-base/logs"
+	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin
+	_ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
+	"k8s.io/kubernetes/cmd/kubelite/app"
+)
+
+func main() {
+	println("Starting kubelite")
+	// TODO: once we switch everything over to Cobra commands, we can go back to calling
+	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
+	// normalize func and add the go flag set by hand.
+	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
+	// utilflag.InitFlags()
+	logs.InitLogs()
+	defer logs.FlushLogs()
+
+	app.Execute()
+	println("Stopping kubelite")
+}
diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go
index d2d830376da..fa6dbc91fef 100644
--- a/pkg/volume/csi/csi_plugin.go
+++ b/pkg/volume/csi/csi_plugin.go
@@ -347,18 +347,23 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
 	}
 
 	// Initializing the label management channels
-	nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
+	localNim := nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins)
 	PluginHandler.csiPlugin = p
 
 	// This function prevents Kubelet from posting Ready status until CSINode
 	// is both installed and initialized
-	if err := initializeCSINode(host, p.csiDriverInformer); err != nil {
+	if err := initializeCSINode(host, p.csiDriverInformer, localNim); err != nil {
 		return errors.New(log("failed to initialize CSINode: %v", err))
 	}
+
+	if _, ok := host.(volume.KubeletVolumeHost); ok {
+		nim = localNim
+	}
+
 	return nil
 }
 
-func initializeCSINode(host volume.VolumeHost, csiDriverInformer cache.SharedIndexInformer) error {
+func initializeCSINode(host volume.VolumeHost, csiDriverInformer cache.SharedIndexInformer, nim nodeinfomanager.Interface) error {
 	kvh, ok := host.(volume.KubeletVolumeHost)
 	if !ok {
 		klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet")
-- 
2.43.0



================================================
FILE: build-scripts/components/kubernetes/patches/v1.34.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch
================================================
From e2e2155d05b3ddd16640272bd1360425a3883c78 Mon Sep 17 00:00:00 2001
From: Angelos Kolaitis <angelos.kolaitis@canonical.com>
Date: Thu, 27 Jul 2023 18:08:00 +0300
Subject: [PATCH 2/2] Set log reapply handling to ignore unchanged

---
 staging/src/k8s.io/component-base/logs/api/v1/options.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/staging/src/k8s.io/component-base/logs/api/v1/options.go b/staging/src/k8s.io/component-base/logs/api/v1/options.go
index 4c8a0d2c53f..6cb6ae1f42d 100644
--- a/staging/src/k8s.io/component-base/logs/api/v1/options.go
+++ b/staging/src/k8s.io/component-base/logs/api/v1/options.go
@@ -65,7 +65,7 @@ func NewLoggingConfiguration() *LoggingConfiguration {
 // are no goroutines which might call logging functions. The default for ValidateAndApply
 // and ValidateAndApplyWithOptions is to return an error when called more than once.
 // Binaries and unit tests can override that behavior.
-var ReapplyHandling = ReapplyHandlingError
+var ReapplyHandling = ReapplyHandlingIgnoreUnchanged
 
 type ReapplyHandlingType int
 
-- 
2.43.0



================================================
FILE: build-scripts/components/kubernetes/patches/v1.34.0/0002-fix-allow-node-to-get-endpointslices.patch
================================================
From dea2abd80878be1eff519216c0bad5a0e35462ec Mon Sep 17 00:00:00 2001
From: Mateo Florido <mateo.florido@canonical.com>
Date: Thu, 11 Sep 2025 17:36:10 -0500
Subject: [PATCH] fix: allow node to get endpointslices

---
 plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go
index 447b0bc2e99..daa3bde6b1c 100644
--- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go
+++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go
@@ -228,6 +228,7 @@ func NodeRules() []rbacv1.PolicyRule {
 		// TODO: add to the Node authorizer and restrict to endpoints referenced by pods or PVs bound to the node
 		// Needed for glusterfs volumes
 		rbacv1helpers.NewRule("get").Groups(legacyGroup).Resources("endpoints").RuleOrDie(),
+		rbacv1helpers.NewRule("get", "list", "watch").Groups(discoveryGroup).Resources("endpointslices").RuleOrDie(),
 		// Used to create a certificatesigningrequest for a node-specific client certificate, and watch
 		// for it to be signed. This allows the kubelet to rotate it's own certificate.
 		rbacv1helpers.NewRule("create", "get", "list", "watch").Groups(certificatesGroup).Resources("certificatesigningrequests").RuleOrDie(),
-- 
2.48.1



================================================
FILE: build-scripts/components/kubernetes/patches/v1.35.0/0000-Kubelite-integration.patch
================================================
From afd6e0c5da37c3ae02c22c91ef898c1169e8d657 Mon Sep 17 00:00:00 2001
From: Homayoon Alimohammadi <homayoonalimohammadi@gmail.com>
Date: Thu, 27 Nov 2025 18:47:43 +0400
Subject: [PATCH] Kubelite integration

Signed-off-by: Homayoon Alimohammadi <homayoonalimohammadi@gmail.com>
---
 cmd/kube-apiserver/app/server.go              |  9 +-
 .../app/options/options.go                    | 10 --
 cmd/kube-scheduler/app/server.go              |  6 +-
 cmd/kubelet/app/server.go                     |  4 -
 cmd/kubelite/app/daemons/daemon.go            | 85 +++++++++++++++++
 cmd/kubelite/app/options/options.go           | 79 ++++++++++++++++
 cmd/kubelite/app/server.go                    | 91 +++++++++++++++++++
 cmd/kubelite/kubelite.go                      | 25 +++++
 pkg/volume/csi/csi_plugin.go                  | 11 ++-
 9 files changed, 300 insertions(+), 20 deletions(-)
 create mode 100644 cmd/kubelite/app/daemons/daemon.go
 create mode 100644 cmd/kubelite/app/options/options.go
 create mode 100644 cmd/kubelite/app/server.go
 create mode 100644 cmd/kubelite/kubelite.go

diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go
index a0ba37e0103..32ae1a53496 100644
--- a/cmd/kube-apiserver/app/server.go
+++ b/cmd/kube-apiserver/app/server.go
@@ -67,9 +67,14 @@ func init() {
 }
 
 // NewAPIServerCommand creates a *cobra.Command object with default parameters
-func NewAPIServerCommand() *cobra.Command {
+func NewAPIServerCommand(ctxs ...context.Context) *cobra.Command {
 	s := options.NewServerRunOptions()
-	ctx := genericapiserver.SetupSignalContext()
+	ctx := context.Background()
+	if len(ctxs) == 0 {
+		ctx = genericapiserver.SetupSignalContext()
+	} else {
+		ctx = ctxs[0]
+	}
 	featureGate := s.GenericServerRunOptions.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent)
 
 	cmd := &cobra.Command{
diff --git a/cmd/kube-controller-manager/app/options/options.go b/cmd/kube-controller-manager/app/options/options.go
index 867cd8d3250..8c4f50a923e 100644
--- a/cmd/kube-controller-manager/app/options/options.go
+++ b/cmd/kube-controller-manager/app/options/options.go
@@ -26,12 +26,10 @@ import (
 	v1 "k8s.io/api/core/v1"
 	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
-	"k8s.io/apimachinery/pkg/util/version"
 	"k8s.io/apiserver/pkg/server/flagz"
 	apiserveroptions "k8s.io/apiserver/pkg/server/options"
 	"k8s.io/apiserver/pkg/util/compatibility"
 	utilfeature "k8s.io/apiserver/pkg/util/feature"
-	clientgofeaturegate "k8s.io/client-go/features"
 	clientset "k8s.io/client-go/kubernetes"
 	clientgokubescheme "k8s.io/client-go/kubernetes/scheme"
 	restclient "k8s.io/client-go/rest"
@@ -42,7 +40,6 @@ import (
 	cpoptions "k8s.io/cloud-provider/options"
 	cliflag "k8s.io/component-base/cli/flag"
 	basecompatibility "k8s.io/component-base/compatibility"
-	"k8s.io/component-base/featuregate"
 	"k8s.io/component-base/logs"
 	logsapi "k8s.io/component-base/logs/api/v1"
 	"k8s.io/component-base/metrics"
@@ -311,13 +308,6 @@ func (s *KubeControllerManagerOptions) Flags(allControllers []string, disabledBy
 	fss.FlagSet("generic").DurationVar(&s.ControllerShutdownTimeout, "controller-shutdown-timeout",
 		s.ControllerShutdownTimeout, "Time to wait for the controllers to shut down before terminating the executable")
 
-	if !utilfeature.DefaultFeatureGate.Enabled(featuregate.Feature(clientgofeaturegate.WatchListClient)) {
-		ver := version.MustParse("1.34")
-		if err := utilfeature.DefaultMutableFeatureGate.OverrideDefaultAtVersion(featuregate.Feature(clientgofeaturegate.WatchListClient), true, ver); err != nil {
-			panic(fmt.Sprintf("unable to set %s feature gate, err: %v", clientgofeaturegate.WatchListClient, err))
-		}
-	}
-
 	s.ComponentGlobalsRegistry.AddFlags(fss.FlagSet("generic"))
 
 	return fss
diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go
index 834213e337f..1eb9c630220 100644
--- a/cmd/kube-scheduler/app/server.go
+++ b/cmd/kube-scheduler/app/server.go
@@ -150,7 +150,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 	go func() {
-		stopCh := server.SetupSignalHandler()
+                c := cmd.Context()
+                if c == nil {
+                        c = server.SetupSignalContext()
+                }
+                stopCh := c.Done()
 		<-stopCh
 		cancel()
 	}()
diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go
index 54ff8d6a26b..203fe982a9a 100644
--- a/cmd/kubelet/app/server.go
+++ b/cmd/kubelet/app/server.go
@@ -64,7 +64,6 @@ import (
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/apimachinery/pkg/util/validation/field"
 	"k8s.io/apimachinery/pkg/util/wait"
-	genericapiserver "k8s.io/apiserver/pkg/server"
 	"k8s.io/apiserver/pkg/server/flagz"
 	"k8s.io/apiserver/pkg/server/healthz"
 	utilfeature "k8s.io/apiserver/pkg/util/feature"
@@ -287,9 +286,6 @@ is checked every 20 seconds (also configurable with a flag).`,
 			// log the kubelet's config for inspection
 			logger.V(5).Info("KubeletConfiguration", "configuration", klog.Format(config))
 
-			// set up signal context for kubelet shutdown
-			ctx := genericapiserver.SetupSignalContext()
-
 			utilfeature.DefaultMutableFeatureGate.AddMetrics()
 			// run the kubelet
 			return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate)
diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go
new file mode 100644
index 00000000000..46c1af7fdb9
--- /dev/null
+++ b/cmd/kubelite/app/daemons/daemon.go
@@ -0,0 +1,85 @@
+package daemon
+
+import (
+	"context"
+
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/clientcmd"
+	genericcontrollermanager "k8s.io/controller-manager/app"
+	"k8s.io/klog/v2"
+	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
+	controller "k8s.io/kubernetes/cmd/kube-controller-manager/app"
+	proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
+	scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
+	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
+
+	"time"
+)
+
+func StartControllerManager(args []string, ctx context.Context) {
+	command := controller.NewControllerManagerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Controller Manager")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Controller Manager exited %v", err)
+	}
+	klog.Info("Stopping Controller Manager")
+}
+
+func StartScheduler(args []string, ctx context.Context) {
+	command := scheduler.NewSchedulerCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Scheduler")
+	if err := command.ExecuteContext(ctx); err != nil {
+		klog.Fatalf("Scheduler exited %v", err)
+	}
+	klog.Info("Stopping Scheduler")
+}
+
+func StartProxy(args []string) {
+	command := proxy.NewProxyCommand()
+	command.SetArgs(args)
+
+	klog.Info("Starting Proxy")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Proxy exited %v", err)
+	}
+	klog.Info("Stopping Proxy")
+}
+
+func StartKubelet(args []string, ctx context.Context) {
+	command := kubelet.NewKubeletCommand(ctx)
+	command.SetArgs(args)
+
+	klog.Info("Starting Kubelet")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("Kubelet exited %v", err)
+	}
+	klog.Info("Stopping Kubelet")
+}
+
+func StartAPIServer(args []string, ctx context.Context) {
+	command := apiserver.NewAPIServerCommand(ctx)
+	command.SetArgs(args)
+	klog.Info("Starting API Server")
+	if err := command.Execute(); err != nil {
+		klog.Fatalf("API Server exited %v", err)
+	}
+	klog.Info("Stopping API Server")
+}
+
+func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) {
+	klog.Info("Waiting for the API server")
+	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath)
+	if err != nil {
+		klog.Fatalf("could not find the cluster's kubeconfig file %v", err)
+	}
+	// create the client
+	client, err := kubernetes.NewForConfig(config)
+	if err != nil {
+		klog.Fatalf("could not create client to the cluster %v", err)
+	}
+	genericcontrollermanager.WaitForAPIServer(client, timeout)
+}
diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go
new file mode 100644
index 00000000000..80f1d8b09fc
--- /dev/null
+++ b/cmd/kubelite/app/options/options.go
@@ -0,0 +1,79 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package options
+
+import (
+	"bufio"
+	"k8s.io/klog/v2"
+	"os"
+	"strings"
+)
+
+// Options has all the params needed to run a Kubelite
+type Options struct {
+	SchedulerArgsFile         string
+	ControllerManagerArgsFile string
+	ProxyArgsFile             string
+	KubeletArgsFile           string
+	APIServerArgsFile         string
+	KubeconfigFile    		  string
+	StartControlPlane		  bool
+}
+
+func NewOptions() (*Options){
+	o := Options{
+		"/var/snap/microk8s/current/args/kube-scheduler",
+		"/var/snap/mi
Download .txt
gitextract_osiht2xu/

├── .github/
│   ├── .jira_sync_config.yaml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── feature_request.md
│   │   └── question.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── actions/
│   │   └── test-prep/
│   │       └── action.yaml
│   ├── dependabot.yml
│   └── workflows/
│       ├── backport.yml
│       ├── build-installer.yml
│       ├── build-snap.yml
│       ├── check-formatting.yml
│       ├── check-unit-tests.yml
│       ├── cla-check.yml
│       ├── stale-cron.yaml
│       └── update-images.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build-scripts/
│   ├── .gitignore
│   ├── addons/
│   │   └── repositories.sh
│   ├── build-component.sh
│   ├── components/
│   │   ├── README.md
│   │   ├── cluster-agent/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── cni/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   └── default/
│   │   │   │       └── 0001-single-entrypoint-for-cni-tools.patch
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── containerd/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   ├── default/
│   │   │   │   │   └── 0001-microk8s-sideload-images-plugin.patch
│   │   │   │   └── v2.1.3/
│   │   │   │       └── 0001-microk8s-sideload-images-plugin.patch
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── etcd/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── flannel-cni-plugin/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── flanneld/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   └── default/
│   │   │   │       └── 0001-disable-udp-backend.patch
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── helm/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── k8s-dqlite/
│   │   │   ├── build.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── kubernetes/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   ├── v1.27.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Unix-socket-skip-validation-in-component-status.patch
│   │   │   │   ├── v1.27.4/
│   │   │   │   │   └── 0000-Kubelite-integration.patch
│   │   │   │   ├── v1.28.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   ├── v1.31.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   ├── v1.32.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   ├── v1.33.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   └── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   ├── v1.34.0/
│   │   │   │   │   ├── 0000-Kubelite-integration.patch
│   │   │   │   │   ├── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │   │   └── 0002-fix-allow-node-to-get-endpointslices.patch
│   │   │   │   └── v1.35.0/
│   │   │   │       ├── 0000-Kubelite-integration.patch
│   │   │   │       ├── 0001-Set-log-reapply-handling-to-ignore-unchanged.patch
│   │   │   │       └── 0002-fix-allow-node-to-get-endpointslices.patch
│   │   │   ├── pre-patch.sh
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── microk8s-completion/
│   │   │   ├── build.sh
│   │   │   ├── patches/
│   │   │   │   └── default/
│   │   │   │       └── 0001-microk8s-autocompleter-script.patch
│   │   │   ├── repository
│   │   │   └── version.sh
│   │   ├── python/
│   │   │   └── requirements.txt
│   │   └── runc/
│   │       ├── build.sh
│   │       ├── patches/
│   │       │   └── default/
│   │       │       └── 0001-Disable-static-PIE-on-arm64.patch
│   │       ├── repository
│   │       ├── strict-patches/
│   │       │   ├── v1.1.12/
│   │       │   │   ├── 0001-apparmor-change-profile-immediately-not-on-exec.patch
│   │       │   │   ├── 0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch
│   │       │   │   └── 0003-standard_init_linux-change-AppArmor-profile-as-late-.patch
│   │       │   ├── v1.1.15/
│   │       │   │   ├── 0001-apparmor-change-profile-immediately-not-on-exec.patch
│   │       │   │   ├── 0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch
│   │       │   │   └── 0003-standard_init_linux-change-AppArmor-profile-as-late-.patch
│   │       │   ├── v1.2.6/
│   │       │   │   ├── 0001-apparmor-change-profile-immediately-not-on-exec.patch
│   │       │   │   ├── 0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch
│   │       │   │   └── 0003-standard_init_linux-change-AppArmor-profile-as-late-.patch
│   │       │   └── v1.3.0/
│   │       │       ├── 0001-apparmor-change-profile-immediately-not-on-exec.patch
│   │       │       ├── 0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch
│   │       │       └── 0003-standard_init_linux-change-AppArmor-profile-as-late-.patch
│   │       └── version.sh
│   ├── generate-bom.py
│   ├── images.txt
│   ├── print-patches-for.py
│   └── update-images.sh
├── docs/
│   ├── build.md
│   ├── community.md
│   └── k8s-patches.md
├── installer/
│   ├── .gitignore
│   ├── __init__.py
│   ├── build-linux.sh
│   ├── cli/
│   │   ├── __init__.py
│   │   ├── echo.py
│   │   └── microk8s.py
│   ├── common/
│   │   ├── __init__.py
│   │   ├── auxiliary.py
│   │   ├── definitions.py
│   │   ├── errors.py
│   │   └── file_utils.py
│   ├── microk8s.py
│   ├── microk8s.spec
│   ├── requirements.txt
│   ├── setup.cfg
│   ├── setup.py
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── integration/
│   │   │   └── test_cli.py
│   │   └── unit/
│   │       ├── test_auxiliary.py
│   │       └── test_cli.py
│   ├── vm_providers/
│   │   ├── __init__.py
│   │   ├── _base_provider.py
│   │   ├── _multipass/
│   │   │   ├── __init__.py
│   │   │   ├── _instance_info.py
│   │   │   ├── _multipass.py
│   │   │   ├── _multipass_command.py
│   │   │   └── _windows.py
│   │   ├── errors.py
│   │   ├── factory.py
│   │   └── repo/
│   │       ├── __init__.py
│   │       ├── errors.py
│   │       └── snaps.py
│   └── windows/
│       ├── README.md
│       └── microk8s.nsi
├── microk8s-resources/
│   ├── actions/
│   │   └── common/
│   │       └── utils.sh
│   ├── basic_auth.csv
│   ├── certs/
│   │   ├── csr-dqlite.conf.template
│   │   └── csr.conf.template
│   ├── client-x509.config.template
│   ├── client.config
│   ├── client.config.template
│   ├── containerd-profile
│   ├── default-args/
│   │   ├── admission-control-config-file.yaml
│   │   ├── apiserver-proxy
│   │   ├── certs.d/
│   │   │   ├── docker.io/
│   │   │   │   └── hosts.toml
│   │   │   └── localhost__32000/
│   │   │       └── hosts.toml
│   │   ├── cluster-agent
│   │   ├── cni-env
│   │   ├── cni-network/
│   │   │   └── flannel.conflist
│   │   ├── containerd
│   │   ├── containerd-env
│   │   ├── containerd-template.toml
│   │   ├── ctr
│   │   ├── etcd
│   │   ├── eventconfig.yaml
│   │   ├── flannel-network-mgr-config
│   │   ├── flannel-template.conflist
│   │   ├── flanneld
│   │   ├── git/
│   │   │   └── .gitconfig
│   │   ├── ha-conf
│   │   ├── k8s-dqlite
│   │   ├── k8s-dqlite-env
│   │   ├── kube-apiserver
│   │   ├── kube-controller-manager
│   │   ├── kube-proxy
│   │   ├── kube-scheduler
│   │   ├── kubectl
│   │   ├── kubectl-env
│   │   ├── kubelet
│   │   ├── kubelite
│   │   └── traefik/
│   │       ├── provider-template.yaml
│   │       └── traefik-template.yaml
│   ├── default-hooks/
│   │   ├── post-refresh.d/
│   │   │   └── 30-helm
│   │   ├── reconcile.d/
│   │   │   ├── 10-pods-restart
│   │   │   └── 90-calico-apply
│   │   └── remove.d/
│   │       ├── 10-cni-link
│   │       ├── 10-cni-link-cilium
│   │       ├── 20-cni-netns
│   │       └── 90-containers
│   ├── kubelet.config
│   ├── kubelet.config.template
│   ├── kubeproxy.config
│   ├── microk8s.default.yaml
│   └── wrappers/
│       ├── apiservice-kicker
│       ├── git.wrapper
│       ├── microk8s-add-node.wrapper
│       ├── microk8s-addons.wrapper
│       ├── microk8s-config.wrapper
│       ├── microk8s-ctr.wrapper
│       ├── microk8s-dashboard-proxy.wrapper
│       ├── microk8s-dbctl.wrapper
│       ├── microk8s-disable.wrapper
│       ├── microk8s-enable.wrapper
│       ├── microk8s-helm.wrapper
│       ├── microk8s-helm3.wrapper
│       ├── microk8s-images.wrapper
│       ├── microk8s-istioctl.wrapper
│       ├── microk8s-join.wrapper
│       ├── microk8s-kubectl.wrapper
│       ├── microk8s-leave.wrapper
│       ├── microk8s-linkerd.wrapper
│       ├── microk8s-refresh-certs.wrapper
│       ├── microk8s-remove-node.wrapper
│       ├── microk8s-reset.wrapper
│       ├── microk8s-start.wrapper
│       ├── microk8s-status.wrapper
│       ├── microk8s-stop.wrapper
│       ├── microk8s-version.wrapper
│       ├── microk8s.wrapper
│       ├── openssl.wrapper
│       ├── run-apiserver-proxy-with-args
│       ├── run-cluster-agent-with-args
│       ├── run-containerd-with-args
│       ├── run-etcd-with-args
│       ├── run-flanneld-with-args
│       ├── run-k8s-dqlite-with-args
│       └── run-kubelite-with-args
├── pyproject.toml
├── scripts/
│   ├── calico/
│   │   └── upgrade.py
│   ├── find-resolv-conf.py
│   ├── generate-cni.sh
│   ├── inspect.sh
│   ├── kill-host-pods.py
│   ├── run-lifecycle-hooks.py
│   └── wrappers/
│       ├── add_token.py
│       ├── addons.py
│       ├── common/
│       │   ├── __init__.py
│       │   ├── cluster/
│       │   │   ├── __init__.py
│       │   │   └── utils.py
│       │   └── utils.py
│       ├── dashboard_proxy.py
│       ├── dbctl.py
│       ├── disable.py
│       ├── distributed_op.py
│       ├── enable.py
│       ├── images.py
│       ├── join.py
│       ├── leave.py
│       ├── refresh_certs.py
│       ├── remove_node.py
│       ├── reset.py
│       ├── status.py
│       ├── upgrade.py
│       └── version.py
├── snap/
│   ├── hooks/
│   │   ├── configure
│   │   ├── connect-plug-network-control
│   │   ├── disconnect-plug-network-control
│   │   ├── install
│   │   ├── post-refresh
│   │   └── remove
│   └── snapcraft.yaml
├── tests/
│   ├── libs/
│   │   ├── addons-upgrade.sh
│   │   ├── addons.sh
│   │   ├── airgap.sh
│   │   ├── clustering.sh
│   │   ├── spread.sh
│   │   ├── upgrade-path.sh
│   │   └── utils.sh
│   ├── lxc/
│   │   ├── install-deps/
│   │   │   ├── images_almalinux-8
│   │   │   ├── images_archlinux
│   │   │   ├── images_centos-7
│   │   │   ├── images_centos-8-Stream
│   │   │   ├── images_debian-10
│   │   │   ├── images_debian-11
│   │   │   ├── images_debian-12
│   │   │   ├── images_fedora-37
│   │   │   ├── images_fedora-38
│   │   │   ├── images_rockylinux-8
│   │   │   ├── ubuntu_16.04
│   │   │   ├── ubuntu_18.04
│   │   │   ├── ubuntu_20.04
│   │   │   └── ubuntu_22.04
│   │   ├── microk8s-zfs.profile
│   │   └── microk8s.profile
│   ├── requirements.txt
│   ├── smoke-test.sh
│   ├── templates/
│   │   ├── bbox-local.yaml
│   │   ├── dual-stack.yaml
│   │   ├── ingress.yaml
│   │   ├── nginx-pod.yaml
│   │   ├── pvc.yaml
│   │   ├── registry-sc.yaml
│   │   └── simple-deploy.yaml
│   ├── test-cluster-agent.py
│   ├── test-cluster.py
│   ├── test-distro.sh
│   ├── test-simple.py
│   ├── test-upgrade-path.py
│   ├── test-upgrade.py
│   ├── unit/
│   │   ├── cluster/
│   │   │   ├── test_join.py
│   │   │   └── test_leave.py
│   │   ├── test_addons.py
│   │   ├── test_addtoken.py
│   │   ├── test_dashboard_proxy.py
│   │   ├── test_disable.py
│   │   ├── test_enable.py
│   │   ├── test_refresh_certs.py
│   │   ├── test_reset.py
│   │   ├── test_upgrade_calico_cni.py
│   │   ├── test_version.py
│   │   └── yamls/
│   │       ├── calico-new.yaml
│   │       ├── cni.yaml
│   │       └── invalid.yaml
│   ├── utils.py
│   ├── validators.py
│   └── verify-branches.py
├── tox.ini
└── upgrade-scripts/
    ├── 000-switch-to-calico/
    │   ├── commit-master.sh
    │   ├── commit-node.sh
    │   ├── description.txt
    │   ├── prepare-master.sh
    │   ├── prepare-node.sh
    │   ├── resources/
    │   │   └── calico.yaml
    │   ├── rollback-master.sh
    │   └── rollback-node.sh
    ├── 001-switch-to-dqlite/
    │   ├── commit-master.sh
    │   ├── commit-node.sh
    │   ├── description.txt
    │   ├── prepare-master.sh
    │   ├── prepare-node.sh
    │   ├── rollback-master.sh
    │   └── rollback-node.sh
    └── 002-switch-to-flannel-etcd/
        ├── commit-master.sh
        ├── commit-node.sh
        ├── description.txt
        ├── prepare-master.sh
        ├── prepare-node.sh
        ├── rollback-master.sh
        └── rollback-node.sh
Download .txt
SYMBOL INDEX (617 symbols across 60 files)

FILE: build-scripts/generate-bom.py
  function _listdir (line 37) | def _listdir(dir: Path):
  function _parse_output (line 44) | def _parse_output(*args, **kwargs):
  function _read_file (line 48) | def _read_file(path: Path) -> str:

FILE: build-scripts/print-patches-for.py
  class Version (line 16) | class Version:
    method __init__ (line 17) | def __init__(self, version_string: str):
    method equal_or_older_than (line 31) | def equal_or_older_than(self, v: "Version") -> bool:
  function find_suitable_patch_version (line 46) | def find_suitable_patch_version(candidates: list, target_version: Versio...
  function get_patches_for (line 74) | def get_patches_for(component: str, version_string: str, strict: bool) -...
  function main (line 107) | def main():

FILE: installer/cli/echo.py
  class Echo (line 29) | class Echo:
    method is_tty_connected (line 31) | def is_tty_connected() -> bool:
    method wrapped (line 36) | def wrapped(msg: str) -> None:
    method info (line 47) | def info(msg: str) -> None:
    method warning (line 54) | def warning(msg: str) -> None:
    method error (line 61) | def error(msg: str) -> None:
    method confirm (line 67) | def confirm(
    method prompt (line 92) | def prompt(

FILE: installer/cli/microk8s.py
  function cli (line 30) | def cli(ctx, help):
  function show_error (line 77) | def show_error():
  function show_help (line 85) | def show_help():
  function _show_install_help (line 106) | def _show_install_help():
  function memory (line 120) | def memory(mem_gb: str) -> int:
  function cpu (line 130) | def cpu(cpus: str) -> int:
  function disk (line 140) | def disk(disk_gb: str) -> int:
  function install (line 150) | def install(args) -> None:
  function uninstall (line 210) | def uninstall() -> None:
  function kubectl (line 236) | def kubectl(args) -> int:
  function inspect (line 245) | def inspect() -> None:
  function dashboard_proxy (line 283) | def dashboard_proxy() -> None:
  function start (line 343) | def start() -> None:
  function stop (line 354) | def stop() -> None:
  function run (line 364) | def run(cmd) -> None:
  function _not_installed (line 383) | def _not_installed(echo) -> None:
  function _get_microk8s_commands (line 388) | def _get_microk8s_commands() -> List:

FILE: installer/common/auxiliary.py
  class Auxiliary (line 17) | class Auxiliary(ABC):
    method __init__ (line 22) | def __init__(self, args) -> None:
    method _free_disk_space (line 38) | def _free_disk_space() -> int:
    method _total_memory (line 47) | def _total_memory() -> int:
    method _cpu_count (line 56) | def _cpu_count() -> int:
    method has_enough_disk_space (line 64) | def has_enough_disk_space(self) -> bool:
    method has_enough_memory (line 72) | def has_enough_memory(self) -> bool:
    method has_enough_cpus (line 80) | def has_enough_cpus(self) -> bool:
    method get_kubectl_directory (line 88) | def get_kubectl_directory(self) -> str:
    method get_kubeconfig_path (line 98) | def get_kubeconfig_path(self) -> str:
    method kubectl (line 109) | def kubectl(self) -> int:
  class Windows (line 130) | class Windows(Auxiliary):
    method __init__ (line 135) | def __init__(self, args) -> None:
    method check_admin (line 143) | def check_admin() -> bool:
    method check_hyperv (line 152) | def check_hyperv() -> bool:
    method enable_hyperv (line 171) | def enable_hyperv() -> None:
  class Linux (line 195) | class Linux(Auxiliary):
    method __init__ (line 200) | def __init__(self, args) -> None:
  class MacOS (line 208) | class MacOS(Linux):
    method __init__ (line 213) | def __init__(self, args) -> None:

FILE: installer/common/errors.py
  class BaseError (line 1) | class BaseError(Exception):
    method __init__ (line 10) | def __init__(self, **kwargs) -> None:
    method __str__ (line 14) | def __str__(self):
    method get_exit_code (line 17) | def get_exit_code(self):

FILE: installer/common/file_utils.py
  function _file_reader_iter (line 30) | def _file_reader_iter(path: str, block_size=2 ** 20):
  function calculate_sha3_384 (line 38) | def calculate_sha3_384(path: str) -> str:
  function calculate_hash (line 43) | def calculate_hash(path: str, *, algorithm: str) -> str:
  function is_dumb_terminal (line 53) | def is_dumb_terminal():
  function get_kubectl_directory (line 60) | def get_kubectl_directory() -> str:
  function get_kubeconfig_path (line 80) | def get_kubeconfig_path():
  function clear_kubeconfig (line 88) | def clear_kubeconfig():

FILE: installer/tests/integration/test_cli.py
  class TestClass (line 12) | class TestClass:
    method test_install_remove_multipass (line 18) | def test_install_remove_multipass(self, tty_mock):
    method test_all_cli (line 42) | def test_all_cli(self):
    method test_install_argument_are_validated (line 53) | def test_install_argument_are_validated(self):

FILE: installer/tests/unit/test_auxiliary.py
  function get_mocked_args (line 5) | def get_mocked_args(disk=1, mem=1, cpu=1):
  function test_has_enough_memory (line 11) | def test_has_enough_memory(virtual_memory_mock):
  function test_has_enough_cpus (line 25) | def test_has_enough_cpus(cpu_count_mock):
  function test_has_enough_disk_space (line 37) | def test_has_enough_disk_space(disk_usage_mock):

FILE: installer/tests/unit/test_cli.py
  function test_install_exits_on_cpus_requested_exceed_available_on_host (line 7) | def test_install_exits_on_cpus_requested_exceed_available_on_host(has_en...
  function test_install_exits_on_memory_requested_exceed_available_on_host (line 16) | def test_install_exits_on_memory_requested_exceed_available_on_host(

FILE: installer/vm_providers/_base_provider.py
  class Provider (line 33) | class Provider(abc.ABC):
    method __init__ (line 34) | def __init__(
    method ensure_provider (line 53) | def ensure_provider(cls) -> None:
    method setup_provider (line 57) | def setup_provider(cls, *, echoer) -> None:
    method _get_provider_name (line 61) | def _get_provider_name(cls) -> str:
    method _get_is_snap_injection_capable (line 65) | def _get_is_snap_injection_capable(cls) -> bool:
    method create (line 69) | def create(self) -> None:
    method destroy (line 73) | def destroy(self) -> None:
    method get_instance_info (line 81) | def get_instance_info(self) -> InstanceInfo:
    method run (line 85) | def run(self, command: Sequence[str], hide_output: bool = False) -> Op...
    method _launch (line 89) | def _launch(self, specs: Dict):
    method _start (line 93) | def _start(self):
    method _push_file (line 97) | def _push_file(self, *, source: str, destination: str) -> None:
    method pull_file (line 101) | def pull_file(self, name: str, destination: str, delete: bool = False)...
    method shell (line 115) | def shell(self) -> None:
    method launch_instance (line 118) | def launch_instance(self, specs: Dict) -> None:
    method _check_connectivity (line 129) | def _check_connectivity(self) -> None:
    method _copy_kubeconfig_to_kubectl (line 148) | def _copy_kubeconfig_to_kubectl(self, specs: Dict):
    method _setup_microk8s (line 158) | def _setup_microk8s(self, specs: Dict) -> None:
    method _get_env_command (line 165) | def _get_env_command(self) -> Sequence[str]:
    method _get_home_directory (line 182) | def _get_home_directory(self) -> pathlib.Path:
    method _base_has_changed (line 203) | def _base_has_changed(self, base: str, provider_base: str) -> bool:
    method _log_run (line 212) | def _log_run(self, command: Sequence[str]) -> None:
    method stop (line 217) | def stop(self) -> None:

FILE: installer/vm_providers/_multipass/_instance_info.py
  class InstanceInfo (line 23) | class InstanceInfo:
    method from_json (line 25) | def from_json(
    method __init__ (line 67) | def __init__(
    method is_mounted (line 86) | def is_mounted(self, mountpoint: str) -> bool:
    method is_stopped (line 89) | def is_stopped(self) -> bool:
    method is_running (line 92) | def is_running(self) -> bool:

FILE: installer/vm_providers/_multipass/_multipass.py
  class Multipass (line 30) | class Multipass(Provider):
    method ensure_provider (line 34) | def ensure_provider(cls):
    method setup_provider (line 38) | def setup_provider(cls, *, echoer) -> None:
    method _get_is_snap_injection_capable (line 42) | def _get_is_snap_injection_capable(cls) -> bool:
    method _get_provider_name (line 46) | def _get_provider_name(cls):
    method run (line 49) | def run(self, command: Sequence[str], hide_output: bool = False) -> Op...
    method _launch (line 58) | def _launch(self, specs: Dict) -> None:
    method get_instance_info (line 83) | def get_instance_info(self) -> InstanceInfo:
    method _start (line 95) | def _start(self):
    method _umount (line 109) | def _umount(self, *, mountpoint: str) -> None:
    method _push_file (line 113) | def _push_file(self, *, source: str, destination: str) -> None:
    method __init__ (line 117) | def __init__(
    method create (line 132) | def create(self, specs: Dict) -> None:
    method destroy (line 138) | def destroy(self) -> None:
    method pull_file (line 151) | def pull_file(self, name: str, destination: str, delete: bool = False)...
    method shell (line 163) | def shell(self) -> None:
    method _get_instance_info (line 166) | def _get_instance_info(self) -> InstanceInfo:
    method start (line 174) | def start(self) -> None:
    method stop (line 181) | def stop(self) -> None:

FILE: installer/vm_providers/_multipass/_multipass_command.py
  function _run (line 32) | def _run(command: Sequence[str], stdin=subprocess.DEVNULL) -> None:
  function _run_output (line 37) | def _run_output(command: Sequence[str], **kwargs) -> bytes:
  class MultipassCommand (line 42) | class MultipassCommand:
    method ensure_multipass (line 49) | def ensure_multipass(cls, platform: str) -> None:
    method _wait_for_multipass_ready (line 74) | def _wait_for_multipass_ready(cls, *, echoer):
    method setup_multipass (line 101) | def setup_multipass(cls, *, echoer, platform: str) -> None:
    method __init__ (line 125) | def __init__(self, *, platform: str) -> None:
    method launch (line 133) | def launch(
    method start (line 172) | def start(self, *, instance_name: str) -> None:
    method stop (line 185) | def stop(self, *, instance_name: str, time: int = None) -> None:
    method delete (line 203) | def delete(self, *, instance_name: str, purge=True) -> None:
    method execute (line 219) | def execute(
    method shell (line 244) | def shell(self, *, instance_name: str) -> None:
    method mount (line 256) | def mount(
    method umount (line 295) | def umount(self, *, mount: str) -> None:
    method copy_files (line 310) | def copy_files(self, *, source: str, destination: str) -> None:
    method info (line 326) | def info(self, *, instance_name: str, output_format: str = None) -> by...

FILE: installer/vm_providers/_multipass/_windows.py
  function windows_reload_multipass_path_env (line 50) | def windows_reload_multipass_path_env():
  function _run_installer (line 72) | def _run_installer(installer_path: str, echoer):
  function _requests_exception_hint (line 113) | def _requests_exception_hint(e: requests.RequestException) -> str:
  function _fetch_installer_url (line 125) | def _fetch_installer_url() -> str:
  function _download_multipass (line 156) | def _download_multipass(dl_dir: str, echoer) -> str:
  function windows_install_multipass (line 184) | def windows_install_multipass(echoer) -> None:
  function _init_progress_bar (line 197) | def _init_progress_bar(total_length, destination, message=None):
  function download_requests_stream (line 219) | def download_requests_stream(request_stream, destination, message=None, ...

FILE: installer/vm_providers/errors.py
  class ConnectivityError (line 24) | class ConnectivityError(BaseError):
  class ProviderBaseError (line 28) | class ProviderBaseError(BaseError):
  class ProviderNotSupportedError (line 32) | class ProviderNotSupportedError(ProviderBaseError):
    method __init__ (line 39) | def __init__(self, *, provider: str) -> None:
  class ProviderNotFound (line 43) | class ProviderNotFound(ProviderBaseError):
    method __init__ (line 47) | def __init__(self, *, provider: str, prompt_installable: bool, error_m...
  class _GenericProviderError (line 57) | class _GenericProviderError(ProviderBaseError):
    method __init__ (line 77) | def __init__(
  class ProviderCommunicationError (line 104) | class ProviderCommunicationError(ProviderBaseError):
    method __init__ (line 111) | def __init__(self, *, provider_name: str, message: str) -> None:
  class ProviderLaunchError (line 115) | class ProviderLaunchError(_GenericProviderError):
    method __init__ (line 116) | def __init__(
  class ProviderStartError (line 131) | class ProviderStartError(_GenericProviderError):
    method __init__ (line 132) | def __init__(
  class ProviderStopError (line 147) | class ProviderStopError(_GenericProviderError):
    method __init__ (line 148) | def __init__(
  class ProviderDeleteError (line 163) | class ProviderDeleteError(_GenericProviderError):
    method __init__ (line 164) | def __init__(
  class ProviderExecError (line 179) | class ProviderExecError(ProviderBaseError):
    method __init__ (line 186) | def __init__(self, *, provider_name: str, command: Sequence[str], exit...
  class ProviderShellError (line 196) | class ProviderShellError(_GenericProviderError):
    method __init__ (line 197) | def __init__(
  class ProviderMountError (line 212) | class ProviderMountError(_GenericProviderError):
    method __init__ (line 213) | def __init__(
  class ProviderUnMountError (line 228) | class ProviderUnMountError(_GenericProviderError):
    method __init__ (line 229) | def __init__(
  class ProviderFileCopyError (line 244) | class ProviderFileCopyError(_GenericProviderError):
    method __init__ (line 245) | def __init__(
  class ProviderInfoError (line 260) | class ProviderInfoError(ProviderBaseError):
    method __init__ (line 267) | def __init__(self, *, provider_name: str, exit_code: int, stderr: byte...
  class ProviderInstanceNotFoundError (line 271) | class ProviderInstanceNotFoundError(ProviderBaseError):
    method __init__ (line 275) | def __init__(self, *, instance_name: str) -> None:
  class ProviderInfoDataKeyError (line 279) | class ProviderInfoDataKeyError(ProviderBaseError):
    method __init__ (line 286) | def __init__(self, *, provider_name: str, missing_key: str, data: Dict...
  class ProviderBadDataError (line 290) | class ProviderBadDataError(ProviderBaseError):
    method __init__ (line 297) | def __init__(self, *, provider_name: str, data: str) -> None:
  class ProviderMultipassDownloadFailed (line 301) | class ProviderMultipassDownloadFailed(ProviderBaseError):
    method __init__ (line 308) | def __init__(self, message):
  class ProviderMultipassInstallationFailed (line 312) | class ProviderMultipassInstallationFailed(ProviderBaseError):
    method __init__ (line 319) | def __init__(self, message):

FILE: installer/vm_providers/factory.py
  function get_provider_for (line 27) | def get_provider_for(provider_name: str) -> "Type[Provider]":

FILE: installer/vm_providers/repo/errors.py
  class RepoError (line 23) | class RepoError(BaseError):
  class NoNativeBackendError (line 27) | class NoNativeBackendError(RepoError):
  class CacheUpdateFailedError (line 32) | class CacheUpdateFailedError(RepoError):
    method __init__ (line 40) | def __init__(self, errors: str) -> None:
  class FileProviderNotFound (line 48) | class FileProviderNotFound(RepoError):
    method __init__ (line 52) | def __init__(self, *, file_path: str) -> None:
  class BuildPackageNotFoundError (line 56) | class BuildPackageNotFoundError(RepoError):
    method __init__ (line 60) | def __init__(self, package):
  class BuildPackagesNotInstalledError (line 64) | class BuildPackagesNotInstalledError(RepoError):
    method __init__ (line 68) | def __init__(self, *, packages: List[str]) -> None:
  class PackageFetchError (line 72) | class PackageFetchError(RepoError):
    method __init__ (line 76) | def __init__(self, message: str) -> None:
  class PackageBrokenError (line 80) | class PackageBrokenError(RepoError):
    method __init__ (line 84) | def __init__(self, package: str, deps: List[str]) -> None:
  class PackageNotFoundError (line 88) | class PackageNotFoundError(RepoError):
    method message (line 90) | def message(self):
    method __init__ (line 95) | def __init__(self, package_name):
    method __str__ (line 98) | def __str__(self):
  class UnpackError (line 102) | class UnpackError(RepoError):
    method __init__ (line 106) | def __init__(self, package):
  class SnapUnavailableError (line 110) | class SnapUnavailableError(RepoError):
    method __init__ (line 119) | def __init__(self, *, snap_name: str, snap_channel: str) -> None:
  class SnapFindError (line 123) | class SnapFindError(RepoError):
    method __init__ (line 130) | def __init__(self, *, snap_name):
  class SnapInstallError (line 134) | class SnapInstallError(RepoError):
    method __init__ (line 138) | def __init__(self, *, snap_name, snap_channel):
  class SnapDownloadError (line 142) | class SnapDownloadError(RepoError):
    method __init__ (line 146) | def __init__(self, *, snap_name, snap_channel):
  class SnapGetAssertionError (line 150) | class SnapGetAssertionError(RepoError):
    method __init__ (line 158) | def __init__(self, *, assertion_params: Sequence[str]) -> None:
  class SnapRefreshError (line 162) | class SnapRefreshError(RepoError):
    method __init__ (line 166) | def __init__(self, *, snap_name, snap_channel):
  class SnapdConnectionError (line 170) | class SnapdConnectionError(RepoError):
    method __init__ (line 174) | def __init__(self, snap_name: str, url: str) -> None:

FILE: installer/vm_providers/repo/snaps.py
  class SnapPackage (line 40) | class SnapPackage:
    method is_valid_snap (line 56) | def is_valid_snap(cls, snap):
    method is_snap_installed (line 60) | def is_snap_installed(cls, snap):
    method __init__ (line 63) | def __init__(self, snap):
    method installed (line 79) | def installed(self):
    method in_store (line 85) | def in_store(self):
    method get_local_snap_info (line 93) | def get_local_snap_info(self):
    method get_store_snap_info (line 102) | def get_store_snap_info(self):
    method _get_store_channels (line 128) | def _get_store_channels(self):
    method get_current_channel (line 135) | def get_current_channel(self):
    method has_assertions (line 144) | def has_assertions(self) -> bool:
    method is_classic (line 149) | def is_classic(self) -> bool:
    method is_valid (line 163) | def is_valid(self) -> bool:
    method local_download (line 170) | def local_download(self, *, snap_path: str, assertion_path: str) -> None:
    method download (line 197) | def download(self, *, directory: str = None):
    method install (line 209) | def install(self):
    method refresh (line 231) | def refresh(self):
  function download_snaps (line 252) | def download_snaps(*, snaps_list: Sequence[str], directory: str) -> None:
  function install_snaps (line 273) | def install_snaps(snaps_list: Union[Sequence[str], Set[str]]) -> List[str]:
  function _snap_command_requires_sudo (line 303) | def _snap_command_requires_sudo():
  function get_assertion (line 317) | def get_assertion(assertion_params: Sequence[str]) -> bytes:
  function _get_parsed_snap (line 330) | def _get_parsed_snap(snap):
  function get_snapd_socket_path_template (line 341) | def get_snapd_socket_path_template():
  function _get_local_snap_file_iter (line 345) | def _get_local_snap_file_iter(snap_name, *, chunk_size: int):
  function _get_local_snap_info (line 356) | def _get_local_snap_info(snap_name):
  function _get_store_snap_info (line 367) | def _get_store_snap_info(snap_name):
  function get_installed_snaps (line 377) | def get_installed_snaps():

FILE: scripts/calico/upgrade.py
  function get_calico_node_spec (line 8) | def get_calico_node_spec(cni_file):
  function is_calico_cni_manifest (line 35) | def is_calico_cni_manifest(cni_file):
  function get_installed_version_of_calico (line 52) | def get_installed_version_of_calico(cni_file):
  function get_calicos_autodetection_method (line 70) | def get_calicos_autodetection_method(cni_file):
  function patch_manifest (line 88) | def patch_manifest(cni_file, autodetection):
  function backup_old_cni (line 129) | def backup_old_cni(cni_file):
  function try_upgrade (line 137) | def try_upgrade(cni_file, new_cni_file, cni_no_manage=None):
  function mark_apply_needed (line 171) | def mark_apply_needed(lock_file):
  function main (line 181) | def main():

FILE: scripts/find-resolv-conf.py
  function safe_is_non_loopback_address (line 18) | def safe_is_non_loopback_address(address: str):
  function find_resolv_conf_with_non_loopback_address (line 39) | def find_resolv_conf_with_non_loopback_address(resolv_confs: list):
  function main (line 60) | def main(resolv_confs):

FILE: scripts/kill-host-pods.py
  function post_filter_has_known_containers (line 19) | def post_filter_has_known_containers(pod, containers: list) -> bool:
  function post_filter_has_snap_data_mounts (line 35) | def post_filter_has_snap_data_mounts(pod) -> bool:
  function post_filter_has_owner (line 59) | def post_filter_has_owner(pod: dict):
  function main (line 73) | def main(selector: list, dry_run: bool, with_snap_data_mounts: bool, wit...

FILE: scripts/run-lifecycle-hooks.py
  function main (line 14) | def main(hook: str):

FILE: scripts/wrappers/add_token.py
  function token_hex (line 16) | def token_hex(nbytes=None):
  function add_token_with_expiry (line 26) | def add_token_with_expiry(token, file, ttl):
  function run_util (line 46) | def run_util(*args, debug=False):
  function get_network_info (line 71) | def get_network_info():
  function print_pretty (line 83) | def print_pretty(token, check):
  function get_output_dict (line 102) | def get_output_dict(token, check):
  function print_json (line 111) | def print_json(token, check):
  function print_yaml (line 116) | def print_yaml(token, check):
  function print_short (line 121) | def print_short(token, check):

FILE: scripts/wrappers/addons.py
  class RepoValidationError (line 25) | class RepoValidationError(Exception):
    method message (line 27) | def message(self) -> str:
  class AddonsYamlNotFoundError (line 31) | class AddonsYamlNotFoundError(RepoValidationError):
    method __init__ (line 32) | def __init__(self, repo_name: str):
    method message (line 36) | def message(self) -> str:
  class AddonsYamlFormatError (line 40) | class AddonsYamlFormatError(RepoValidationError):
    method __init__ (line 41) | def __init__(self, message):
    method message (line 45) | def message(self) -> str:
  class MissingHookError (line 49) | class MissingHookError(RepoValidationError):
    method __init__ (line 50) | def __init__(self, hook_name: str, addon: str):
    method message (line 55) | def message(self) -> str:
  class WrongHookPermissionsError (line 59) | class WrongHookPermissionsError(RepoValidationError):
    method __init__ (line 60) | def __init__(self, hook_name: str, addon: str):
    method message (line 65) | def message(self) -> str:
  function validate_addons_repo (line 69) | def validate_addons_repo(repo_dir: Path) -> None:
  function validate_addons_file (line 78) | def validate_addons_file(repo_dir: Path) -> None:
  function load_addons_yaml (line 128) | def load_addons_yaml(repo_dir: Path):
  function validate_hooks (line 140) | def validate_hooks(repo_dir: Path) -> None:
  function get_addons_list (line 155) | def get_addons_list(repo_dir: Path) -> List[str]:
  function pull_and_validate (line 160) | def pull_and_validate(name: str, repo_dir: Path):
  function clone_and_validate (line 173) | def clone_and_validate(remote_url: str, repo_dir: Path):
  function add (line 193) | def add(name: str, repository: str, reference: str, force: bool):
  function remove (line 221) | def remove(name: str):
  function update (line 234) | def update(name: str, skip_check_root: bool):
  class GettingGitCommitError (line 273) | class GettingGitCommitError(Exception):
    method __init__ (line 274) | def __init__(self, exit_code, stderr):
  function git_current_commit (line 279) | def git_current_commit(repository: Path) -> str:
  function git_rollback (line 291) | def git_rollback(commit: str, repository: Path):
  function list (line 301) | def list(format: str):

FILE: scripts/wrappers/common/cluster/utils.py
  class InvalidConnectionError (line 22) | class InvalidConnectionError(Exception):
  function is_strict (line 26) | def is_strict():
  function get_group (line 33) | def get_group():
  function snap (line 37) | def snap() -> Path:
  function snap_data (line 44) | def snap_data() -> Path:
  function try_set_file_permissions (line 51) | def try_set_file_permissions(file):
  function remove_expired_token_from_file (line 72) | def remove_expired_token_from_file(file):
  function remove_token_from_file (line 92) | def remove_token_from_file(token, file):
  function is_token_expired (line 115) | def is_token_expired(token_line):
  function get_callback_token (line 129) | def get_callback_token():
  function is_node_running_dqlite (line 149) | def is_node_running_dqlite():
  function is_node_dqlite_worker (line 159) | def is_node_dqlite_worker():
  function is_low_memory_guard_enabled (line 175) | def is_low_memory_guard_enabled():
  function get_dqlite_port (line 185) | def get_dqlite_port():
  function get_cluster_agent_port (line 205) | def get_cluster_agent_port():
  function get_cluster_cidr (line 225) | def get_cluster_cidr():
  function get_control_plane_nodes_internal_ips (line 237) | def get_control_plane_nodes_internal_ips():
  function get_internal_ip_from_get_node (line 258) | def get_internal_ip_from_get_node(node_info):
  function is_same_server (line 267) | def is_same_server(hostname, ip):
  function apply_cni_manifest (line 282) | def apply_cni_manifest(timeout_insec=60):
  function cni_is_patched (line 304) | def cni_is_patched():
  function cni_yaml_exists (line 317) | def cni_yaml_exists():
  function patch_cni (line 326) | def patch_cni(ip):
  function try_initialise_cni_autodetect_for_clustering (line 344) | def try_initialise_cni_autodetect_for_clustering(ip, apply_cni=True):
  function is_kubelite (line 360) | def is_kubelite():
  function service (line 371) | def service(operation, service_name):
  function mark_no_cert_reissue (line 386) | def mark_no_cert_reissue():
  function unmark_no_cert_reissue (line 397) | def unmark_no_cert_reissue():
  function restart_all_services (line 408) | def restart_all_services():
  function get_token (line 439) | def get_token(name, tokens_file="known_tokens.csv"):
  function get_arg (line 457) | def get_arg(key, file):
  function set_arg (line 476) | def set_arg(key, value, file):
  function is_token_auth_enabled (line 508) | def is_token_auth_enabled():
  function enable_token_auth (line 518) | def enable_token_auth(token):
  function ca_one_line (line 534) | def ca_one_line(ca):
  function rebuild_x509_auth_client_configs (line 543) | def rebuild_x509_auth_client_configs():
  function get_valid_connection_parts (line 557) | def get_valid_connection_parts(connection):

FILE: scripts/wrappers/common/utils.py
  function get_current_arch (line 25) | def get_current_arch():
  function snap (line 39) | def snap() -> Path:
  function snap_data (line 46) | def snap_data() -> Path:
  function snap_common (line 53) | def snap_common() -> Path:
  function run (line 60) | def run(*args, die=True):
  function is_cluster_ready (line 82) | def is_cluster_ready(with_ready_node=True):
  function is_ha_enabled (line 91) | def is_ha_enabled():
  function get_dqlite_info (line 96) | def get_dqlite_info():
  function get_etcd_info (line 141) | def get_etcd_info():
  function get_server_urls (line 159) | def get_server_urls(args):
  function is_external_etcd (line 171) | def is_external_etcd():
  function is_cluster_locked (line 181) | def is_cluster_locked():
  function wait_for_ready (line 188) | def wait_for_ready(timeout, with_ready_node=True):
  function exit_if_no_root (line 201) | def exit_if_no_root():
  function exit_if_stopped (line 212) | def exit_if_stopped():
  function exit_if_no_permission (line 219) | def exit_if_no_permission():
  function ensure_started (line 240) | def ensure_started():
  function kubectl_get (line 246) | def kubectl_get(cmd, namespace="--all-namespaces"):
  function kubectl_get_clusterroles (line 253) | def kubectl_get_clusterroles():
  function is_community_addon (line 264) | def is_community_addon(arch, addon_name):
  function get_available_addons (line 287) | def get_available_addons(arch):
  function get_addon_by_name (line 315) | def get_addon_by_name(addons, name):
  function is_service_expected_to_start (line 334) | def is_service_expected_to_start(service):
  function set_service_expected_to_start (line 345) | def set_service_expected_to_start(service, start=True):
  function check_help_flag (line 360) | def check_help_flag(addons: list) -> bool:
  function parse_xable_addon_args (line 374) | def parse_xable_addon_args(addon_args: list, available_addons: list):
  function parse_xable_single_arg (line 417) | def parse_xable_single_arg(addon_arg: str, available_addons: list):
  function xable (line 466) | def xable(action: str, addon_args: list):
  function protected_xable (line 473) | def protected_xable(action: str, addon_args: list):
  function unprotected_xable (line 503) | def unprotected_xable(action: str, addon_args: list):
  function is_enabled (line 553) | def is_enabled(addon, item):
  function get_status (line 561) | def get_status(available_addons, isReady):
  function is_within_directory (line 582) | def is_within_directory(directory, target):
  function safe_extract (line 591) | def safe_extract(tar, path=".", members=None, *, numeric_owner=False):

FILE: scripts/wrappers/dashboard_proxy.py
  function get_token (line 24) | def get_token(secret):
  function dashboard_proxy (line 58) | def dashboard_proxy():

FILE: scripts/wrappers/dbctl.py
  function get_kine_endpoint (line 20) | def get_kine_endpoint():
  function kine_exists (line 27) | def kine_exists():
  function generate_backup_name (line 37) | def generate_backup_name():
  function run_command (line 46) | def run_command(command):
  function backup (line 63) | def backup(fname=None, debug=False):
  function restore (line 103) | def restore(fname_tar, debug=False):

FILE: scripts/wrappers/disable.py
  function disable (line 22) | def disable(addons):

FILE: scripts/wrappers/distributed_op.py
  function get_cluster_agent_endpoints (line 34) | def get_cluster_agent_endpoints(include_self=False):
  function do_configure_op (line 90) | def do_configure_op(remote_op):
  function do_image_import (line 122) | def do_image_import(image_data):
  function restart (line 153) | def restart(service):
  function update_argument (line 167) | def update_argument(service, key, value):
  function remove_argument (line 183) | def remove_argument(service, key):
  function set_addon (line 198) | def set_addon(addon, state):
  function usage (line 218) | def usage():

FILE: scripts/wrappers/enable.py
  function enable (line 19) | def enable(addons) -> None:

FILE: scripts/wrappers/images.py
  function import_images (line 18) | def import_images(image: str):
  function get_all_ctr_images (line 33) | def get_all_ctr_images():
  function export_images (line 46) | def export_images(output: str, images: List[str]):

FILE: scripts/wrappers/join.py
  function get_traefik_port (line 60) | def get_traefik_port():
  function join_request (line 79) | def join_request(conn, api_version, req_data, master_ip, verify_peer, fi...
  function extract_error (line 118) | def extract_error(response):
  function get_connection_info (line 131) | def get_connection_info(
  function get_etcd_client_cert (line 190) | def get_etcd_client_cert(master_ip, master_port, token):
  function get_client_cert (line 224) | def get_client_cert(master_ip, master_port, fname: str, token: str, subj...
  function update_flannel (line 269) | def update_flannel(etcd, master_ip, master_port, token):
  function create_kubeconfig (line 287) | def create_kubeconfig(token, ca, master_ip, api_port, filename, user):
  function update_kubeproxy (line 316) | def update_kubeproxy(token, ca, master_ip, api_port):
  function update_cert_auth_kubeproxy (line 331) | def update_cert_auth_kubeproxy(token, master_ip, master_port):
  function update_kubeproxy_cidr (line 346) | def update_kubeproxy_cidr(cidr):
  function update_cert_auth_kubelet (line 352) | def update_cert_auth_kubelet(token, master_ip, master_port):
  function update_kubelet (line 372) | def update_kubelet(token, ca, master_ip, api_port):
  function update_apiserver (line 391) | def update_apiserver(api_authz_mode, apiserver_port):
  function store_remote_ca (line 405) | def store_remote_ca(ca):
  function mark_worker_node (line 416) | def mark_worker_node():
  function generate_callback_token (line 431) | def generate_callback_token():
  function store_base_kubelet_args (line 445) | def store_base_kubelet_args(args_string):
  function update_kubelet_node_ip (line 457) | def update_kubelet_node_ip(args_string, hostname_override):
  function update_kubelet_hostname_override (line 468) | def update_kubelet_hostname_override(args_string):
  function replace_admin_token (line 478) | def replace_admin_token(token):
  function store_cert (line 499) | def store_cert(filename, payload):
  function store_cluster_certs (line 516) | def store_cluster_certs(cluster_cert, cluster_key):
  function create_admin_kubeconfig (line 531) | def create_admin_kubeconfig(ca, ha_admin_token=None):
  function store_callback_token (line 565) | def store_callback_token(token):
  function update_dqlite (line 577) | def update_dqlite(cluster_cert, cluster_key, voters, host):
  function join_dqlite (line 647) | def join_dqlite(connection_parts, verify=False, worker=False):
  function update_apiserver_proxy (line 695) | def update_apiserver_proxy(master_ip, api_port):
  function rebuild_token_based_auth_configs (line 719) | def rebuild_token_based_auth_configs(info):
  function print_worker_usage (line 733) | def print_worker_usage():
  function join_dqlite_worker_node (line 750) | def join_dqlite_worker_node(info, master_ip, master_port, token):
  function join_dqlite_master_node (line 787) | def join_dqlite_master_node(info, master_ip):
  function join_etcd (line 850) | def join_etcd(connection_parts, verify=True):
  function mark_join_in_progress (line 916) | def mark_join_in_progress():
  function unmark_join_in_progress (line 925) | def unmark_join_in_progress():
  function mark_no_dqlite (line 934) | def mark_no_dqlite():
  function join (line 970) | def join(connection, worker, skip_verify, disable_low_memory_guard):

FILE: scripts/wrappers/leave.py
  function reset_current_dqlite_worker_installation (line 33) | def reset_current_dqlite_worker_installation():
  function disable_apiserver_proxy (line 60) | def disable_apiserver_proxy():
  function unmark_worker_node (line 71) | def unmark_worker_node():
  function reset_current_etcd_installation (line 85) | def reset_current_etcd_installation():
  function reset_current_dqlite_installation (line 123) | def reset_current_dqlite_installation():
  function apply_cni (line 163) | def apply_cni():
  function reinit_cluster (line 189) | def reinit_cluster():
  function is_leader_without_successor (line 238) | def is_leader_without_successor():
  function get_dqlite_endpoints (line 284) | def get_dqlite_endpoints():
  function delete_dqlite_node (line 320) | def delete_dqlite_node(delete_node, dqlite_ep):
  function leave (line 340) | def leave():

FILE: scripts/wrappers/refresh_certs.py
  function check_certificate (line 28) | def check_certificate():
  function undo_refresh (line 47) | def undo_refresh():
  function restart (line 65) | def restart(service="all"):
  function update_configs (line 88) | def update_configs():
  function take_backup (line 103) | def take_backup():
  function reproduce_all_root_ca_certs (line 116) | def reproduce_all_root_ca_certs():
  function reproduce_front_proxy_client_cert (line 137) | def reproduce_front_proxy_client_cert():
  function reproduce_server_cert (line 155) | def reproduce_server_cert():
  function refresh_cert (line 172) | def refresh_cert(cert):
  function install_certs (line 195) | def install_certs(ca_dir):
  function validate_certificates (line 208) | def validate_certificates(ca_dir):
  function install_ca (line 238) | def install_ca(ca_dir):
  function refresh_certs (line 290) | def refresh_certs(ca_dir, undo, check, cert, help):
  function show_help (line 336) | def show_help():

FILE: scripts/wrappers/remove_node.py
  function remove_dqlite_node (line 26) | def remove_dqlite_node(node, force=False):
  function remove_node (line 99) | def remove_node(node):
  function remove_kubelet_token (line 121) | def remove_kubelet_token(node):
  function get_dqlite_endpoints (line 142) | def get_dqlite_endpoints():
  function delete_dqlite_node (line 178) | def delete_dqlite_node(delete_node, dqlite_ep):
  function remove_callback_token (line 197) | def remove_callback_token(node):
  function reset (line 232) | def reset(node, force):

FILE: scripts/wrappers/reset.py
  function exit_if_multinode (line 26) | def exit_if_multinode():
  function disable_addon (line 44) | def disable_addon(repo, addon, args=None):
  function disable_addons (line 63) | def disable_addons(destroy_storage):
  function cni (line 92) | def cni(operation="apply"):
  function clean_cluster (line 109) | def clean_cluster():
  function remove_storage_classes (line 150) | def remove_storage_classes():
  function remove_crds (line 167) | def remove_crds():
  function remove_non_namespaced_resources (line 179) | def remove_non_namespaced_resources():
  function remove_priority_classes (line 194) | def remove_priority_classes():
  function reset_cert_reissue (line 211) | def reset_cert_reissue():
  function remove_binaries (line 221) | def remove_binaries():
  function restart_cluster (line 230) | def restart_cluster():
  function remove_extra_resources (line 244) | def remove_extra_resources(ns_name):
  function run_silently (line 258) | def run_silently(cmd):
  function preflight_check (line 271) | def preflight_check():
  function reset (line 291) | def reset(destroy_storage):

FILE: scripts/wrappers/status.py
  function print_short (line 22) | def print_short(isReady, enabled_addons, disabled_addons):
  function print_pretty (line 36) | def print_pretty(isReady, enabled_addons, disabled_addons):
  function print_short_yaml (line 96) | def print_short_yaml(isReady, enabled_addons, disabled_addons):
  function print_yaml (line 117) | def print_yaml(isReady, enabled_addons, disabled_addons):
  function print_addon_status (line 156) | def print_addon_status(enabled):
  function ha_cluster_formed (line 163) | def ha_cluster_formed(info):

FILE: scripts/wrappers/upgrade.py
  function upgrade_master (line 16) | def upgrade_master(upgrade, phase):
  function node_upgrade (line 34) | def node_upgrade(upgrade, phase, node_ep, token):
  function rollback (line 59) | def rollback(upgrade):
  function run_upgrade (line 88) | def run_upgrade(upgrade):
  function get_nodes_info (line 124) | def get_nodes_info(safe=True):
  function list_upgrades (line 159) | def list_upgrades():

FILE: scripts/wrappers/version.py
  function get_snap_version (line 6) | def get_snap_version() -> str:
  function get_snap_revision (line 10) | def get_snap_revision() -> str:
  function print_versions (line 14) | def print_versions() -> None:

FILE: tests/test-cluster-agent.py
  class TestClusterAgent (line 4) | class TestClusterAgent(object):
    method test_cluster_agent_health (line 9) | def test_cluster_agent_health(self):

FILE: tests/test-cluster.py
  class VM (line 33) | class VM:
    method __init__ (line 50) | def __init__(self, backend=None, attach_vm=None):
    method setup (line 65) | def setup(self, channel_or_snap):
    method _setup_lxc (line 83) | def _setup_lxc(self, channel_or_snap):
    method _load_launch_configuration_lxc (line 134) | def _load_launch_configuration_lxc(self):
    method _transfer_install_local_snap_lxc (line 150) | def _transfer_install_local_snap_lxc(self, channel_or_snap):
    method _setup_multipass (line 167) | def _setup_multipass(self, channel_or_snap):
    method _load_launch_configuration_multipass (line 198) | def _load_launch_configuration_multipass(self):
    method _transfer_install_local_snap_multipass (line 216) | def _transfer_install_local_snap_multipass(self, channel_or_snap):
    method run (line 228) | def run(self, cmd):
    method transfer_file (line 256) | def transfer_file(self, file_path, remote_path):
    method release (line 274) | def release(self):
  class TestCluster (line 287) | class TestCluster(object):
    method setup_cluster (line 289) | def setup_cluster(self):
    method test_calico_in_nodes (line 363) | def test_calico_in_nodes(self):
    method test_calico_interfaces_removed_on_snap_remove (line 378) | def test_calico_interfaces_removed_on_snap_remove(self):
    method test_nodes_in_ha (line 404) | def test_nodes_in_ha(self):
    method test_worker_node (line 519) | def test_worker_node(self):
    method test_no_cert_reissue_in_nodes (line 599) | def test_no_cert_reissue_in_nodes(self):
    method test_dual_stack_cluster (line 614) | def test_dual_stack_cluster(self):
  class TestUpgradeCluster (line 658) | class TestUpgradeCluster(object):
    method setup_old_versioned_cluster (line 660) | def setup_old_versioned_cluster(self):
    method test_mixed_version_join (line 756) | def test_mixed_version_join(self):

FILE: tests/test-simple.py
  class TestSimple (line 9) | class TestSimple(object):
    method test_microk8s_nodes_ready (line 10) | def test_microk8s_nodes_ready(self):
    method test_calico_cni_pods_running (line 26) | def test_calico_cni_pods_running(self):
    method test_nginx_ingress (line 44) | def test_nginx_ingress(self):
    method test_microk8s_services_running (line 95) | def test_microk8s_services_running(self):
    method test_microk8s_stop_start (line 138) | def test_microk8s_stop_start(self):

FILE: tests/test-upgrade-path.py
  class TestUpgradePath (line 16) | class TestUpgradePath(object):
    method test_refresh_path (line 25) | def test_refresh_path(self):

FILE: tests/test-upgrade.py
  class TestUpgrade (line 32) | class TestUpgrade(object):
    method test_upgrade (line 37) | def test_upgrade(self):

FILE: tests/unit/cluster/test_join.py
  function test_command_help_arguments (line 10) | def test_command_help_arguments():
  function test_command_errors_if_no_arguments (line 18) | def test_command_errors_if_no_arguments():
  function test_join_dqlite_master_node (line 30) | def test_join_dqlite_master_node(

FILE: tests/unit/cluster/test_leave.py
  function test_command_help_arguments (line 5) | def test_command_help_arguments():

FILE: tests/unit/test_addons.py
  function test_get_available_addons (line 77) | def test_get_available_addons(snap_common_mock, listdir_mock, strict_moc...
  function test_parse_addons_args (line 123) | def test_parse_addons_args(args, result):
  function test_validate_addons_file (line 148) | def test_validate_addons_file(load_addons_mock):
  function test_validate_addons_file_raises_if_invalid_format (line 153) | def test_validate_addons_file_raises_if_invalid_format(load_addons_mock):
  function test_load_addons_raises_on_file_not_found (line 159) | def test_load_addons_raises_on_file_not_found():
  function test_load_addons_raises_on_invalid_yaml_contents (line 166) | def test_load_addons_raises_on_invalid_yaml_contents(repo_dir):
  function test_get_addons_list (line 176) | def test_get_addons_list():
  function test_validate_addons_repo (line 181) | def test_validate_addons_repo(repo_dir):
  function test_validate_addons_repo_raises_on_missing_enable_hook (line 185) | def test_validate_addons_repo_raises_on_missing_enable_hook(addon_missin...
  function test_validate_addons_repo_raises_on_missing_disable_hook (line 191) | def test_validate_addons_repo_raises_on_missing_disable_hook(addon_missi...
  function test_validate_addons_repo_raises_on_enable_not_executable (line 197) | def test_validate_addons_repo_raises_on_enable_not_executable(enable_not...
  function test_validate_addons_repo_raises_on_disable_not_executable (line 203) | def test_validate_addons_repo_raises_on_disable_not_executable(disable_n...
  function test_add_removes_repo_on_validation_error (line 214) | def test_add_removes_repo_on_validation_error(
  function repo_dir (line 230) | def repo_dir(tmp_path):
  function invalid_addons_yaml (line 255) | def invalid_addons_yaml(tmp_path):
  function missing_addons_yaml (line 264) | def missing_addons_yaml(tmp_path):
  function addon_missing_enable_hook (line 271) | def addon_missing_enable_hook(repo_dir):
  function addon_missing_disable_hook (line 278) | def addon_missing_disable_hook(repo_dir):
  function enable_not_executable (line 285) | def enable_not_executable(repo_dir):
  function disable_not_executable (line 292) | def disable_not_executable(repo_dir):
  function create_test_repo (line 299) | def create_test_repo(repo_name: str):
  function test_update_rollbacks_repo_on_validation_error (line 321) | def test_update_rollbacks_repo_on_validation_error(

FILE: tests/unit/test_addtoken.py
  function test_single (line 5) | def test_single(capsys):
  function test_multiple (line 15) | def test_multiple(capsys):

FILE: tests/unit/test_dashboard_proxy.py
  function test_command_help_arguments (line 5) | def test_command_help_arguments():

FILE: tests/unit/test_disable.py
  function test_command_help_arguments (line 6) | def test_command_help_arguments():
  function test_command_errors_if_no_arguments (line 14) | def test_command_errors_if_no_arguments():
  function test_command_shows_addon_help_message (line 22) | def test_command_shows_addon_help_message(xable_mock):

FILE: tests/unit/test_enable.py
  function test_command_help_arguments (line 6) | def test_command_help_arguments():
  function test_command_errors_if_no_arguments (line 14) | def test_command_errors_if_no_arguments():
  function test_command_shows_addon_help_message (line 22) | def test_command_shows_addon_help_message(xable_mock):

FILE: tests/unit/test_refresh_certs.py
  class TestRefreshCerts (line 15) | class TestRefreshCerts(object):
    method test_restart (line 17) | def test_restart(self, mock_check_call):
    method test_reproduce_all_root_ca_certs (line 25) | def test_reproduce_all_root_ca_certs(self, mock_check_call, mock_subpr...
    method test_reproduce_front_proxy_client_cert (line 50) | def test_reproduce_front_proxy_client_cert(self, mock_check_call, mock...
    method test_reproduce_server_cert (line 68) | def test_reproduce_server_cert(self, mock_check_call, mock_restart):
    method is_argument_in_call (line 86) | def is_argument_in_call(self, mock_function, argument_substring):
    method test_refresh_cert_errors (line 109) | def test_refresh_cert_errors(
  function test_command_help_arguments (line 133) | def test_command_help_arguments():

FILE: tests/unit/test_reset.py
  function test_command_help_arguments (line 5) | def test_command_help_arguments():

FILE: tests/unit/test_upgrade_calico_cni.py
  class TestCNIUpgrade (line 12) | class TestCNIUpgrade(object):
    method setup_class (line 13) | def setup_class(self):
    method test_no_op (line 23) | def test_no_op(self):
    method test_get_version (line 38) | def test_get_version(self):
    method test_get_autodetect_method (line 45) | def test_get_autodetect_method(self):
    method test_patch (line 52) | def test_patch(self):
    method test_mark (line 70) | def test_mark(self):

FILE: tests/unit/test_version.py
  function test_get_snap_version (line 5) | def test_get_snap_version():
  function test_get_snap_revision (line 10) | def test_get_snap_revision():

FILE: tests/utils.py
  function get_arch (line 13) | def get_arch():
  function run_until_success (line 20) | def run_until_success(cmd, timeout_insec=60, err_out=None):
  function kubectl (line 47) | def kubectl(cmd, timeout_insec=300, err_out=None):
  function docker (line 62) | def docker(cmd):
  function kubectl_get (line 78) | def kubectl_get(target, timeout_insec=300):
  function wait_for_pod_state (line 93) | def wait_for_pod_state(
  function wait_for_installation (line 132) | def wait_for_installation(cluster_nodes=1, timeout_insec=360):
  function wait_for_namespace_termination (line 157) | def wait_for_namespace_termination(namespace, timeout_insec=360):
  function microk8s_enable (line 177) | def microk8s_enable(addon, timeout_insec=300):
  function microk8s_disable (line 197) | def microk8s_disable(addon):
  function microk8s_clustering_capable (line 209) | def microk8s_clustering_capable():
  function microk8s_reset (line 216) | def microk8s_reset(cluster_nodes=1):
  function update_yaml_with_arch (line 225) | def update_yaml_with_arch(manifest_file):
  function is_container (line 239) | def is_container():
  function is_strict (line 265) | def is_strict():
  function is_ipv6_configured (line 271) | def is_ipv6_configured():
  function _get_process (line 279) | def _get_process(name):

FILE: tests/validators.py
  function validate_dns_dashboard (line 21) | def validate_dns_dashboard():
  function validate_storage (line 56) | def validate_storage():
  function common_ingress (line 95) | def common_ingress():
  function validate_ingress (line 124) | def validate_ingress():
  function validate_registry (line 145) | def validate_registry():
  function validate_forward (line 167) | def validate_forward():
  function validate_metrics_server (line 191) | def validate_metrics_server():
  function validate_metallb_config (line 210) | def validate_metallb_config(ip_ranges="192.168.0.105"):
  function validate_dual_stack (line 224) | def validate_dual_stack():

FILE: tests/verify-branches.py
  class TestMicrok8sBranches (line 5) | class TestMicrok8sBranches(object):
    method test_branches (line 6) | def test_branches(self):
    method _upstream_release (line 40) | def _upstream_release(self):
    method _get_max_minor (line 49) | def _get_max_minor(self, major):
    method _upstream_release_exists (line 58) | def _upstream_release_exists(self, major, minor):
Condensed preview — 330 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,695K chars).
[
  {
    "path": ".github/.jira_sync_config.yaml",
    "chars": 1134,
    "preview": "settings:\n  # Jira project key to create the issue in\n  jira_project_key: \"KU\"\n\n  # Dictionary mapping GitHub issue stat"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 881,
    "preview": "---\nname: Bug Report\nabout: Something is not working\n---\n\n<!--\n   Thank you for submitting an issue. Please fill in the "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 496,
    "preview": "---\nname: Feature Request\nabout: Suggest a new feature\n---\n\n<!--\n   Thank you for submitting a feature request. Please f"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.yml",
    "chars": 227,
    "preview": "contact_links:\n  - name: Ask a question\n    url: https://kubernetes.slack.com/archives/CAUNWQ85V\n    about: \"For discuss"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 1075,
    "preview": "<!--\n  Thank you for making MicroK8s better. Please fill the template below\n  with more details.\n-->\n\n#### Summary\n<!--\n"
  },
  {
    "path": ".github/actions/test-prep/action.yaml",
    "chars": 748,
    "preview": "name: Prepare test prerequisites\n\nruns:\n  using: \"composite\"\n  steps:\n    - name: Setup Python\n      uses: actions/setup"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 217,
    "preview": "# Set update schedule for GitHub Actions\n\nversion: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\""
  },
  {
    "path": ".github/workflows/backport.yml",
    "chars": 1892,
    "preview": "name: Backport merged pull request\non:\n  pull_request_target:\n    types: [closed]\n  issue_comment:\n    types: [created]\n"
  },
  {
    "path": ".github/workflows/build-installer.yml",
    "chars": 2223,
    "preview": "name: Build MicroK8s Installers\n\non:\n  push:\n    branches:\n      - \"**install**\"\n  pull_request:\n    branches:\n      - \""
  },
  {
    "path": ".github/workflows/build-snap.yml",
    "chars": 8490,
    "preview": "name: Build and test MicroK8s snap\n\non:\n  pull_request:\n    branches:\n      - master\n\njobs:\n  build:\n    name: Create sn"
  },
  {
    "path": ".github/workflows/check-formatting.yml",
    "chars": 848,
    "preview": "name: Lint Code\n\non:\n  - pull_request\n\njobs:\n  check-formatting:\n    name: Check Formatting\n    runs-on: ubuntu-latest\n\n"
  },
  {
    "path": ".github/workflows/check-unit-tests.yml",
    "chars": 590,
    "preview": "name: Unit Tests\n\non:\n  - pull_request\n\njobs:\n  check-unit-tests:\n    name: Check Unit Tests\n    runs-on: ubuntu-latest\n"
  },
  {
    "path": ".github/workflows/cla-check.yml",
    "chars": 213,
    "preview": "name: cla-check\n\non:\n  pull_request:\n    branches: [master, default]\n\njobs:\n  cla-check:\n    runs-on: ubuntu-latest\n    "
  },
  {
    "path": ".github/workflows/stale-cron.yaml",
    "chars": 971,
    "preview": "name: Close inactive issues or PRs\non:\n  schedule:\n    - cron: \"0 0 * * *\" # Runs every midnight\n  pull_request:\n    pat"
  },
  {
    "path": ".github/workflows/update-images.yml",
    "chars": 1746,
    "preview": "name: Update list of images\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: \"0 10 * * *\"\n\npermissions:\n  contents: wri"
  },
  {
    "path": ".gitignore",
    "chars": 293,
    "preview": "/build/\n/parts/\n/prime/\n/stage/\n!/snap/hooks/\n*.snap\nmicrok8s.egg-info/\nmicrok8s_source.tar.bz2\ntests/__pycache__\n.idea/"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 107,
    "preview": "MicroK8s has adopted the [Ubuntu Code of Conduct v2.0](https://ubuntu.com/community/ethos/code-of-conduct)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3008,
    "preview": "# Contributor Guide\n\nMicroK8s is open source ([Apache License 2.0](./LICENSE)) and actively seeks any community contribu"
  },
  {
    "path": "LICENSE",
    "chars": 11345,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 3602,
    "preview": "<img src=\"docs/images/MicroK8s-logo-RGB-2022.png\" width=\"400px;\" />\n\n[![](https://github.com/canonical/microk8s/actions/"
  },
  {
    "path": "build-scripts/.gitignore",
    "chars": 16,
    "preview": ".build\n.install\n"
  },
  {
    "path": "build-scripts/addons/repositories.sh",
    "chars": 844,
    "preview": "#!/bin/bash -x\n\n# List of addon repositories to bundle in the snap\n# (name),(repository),(reference)\nADDONS_REPOS=\"\ncore"
  },
  {
    "path": "build-scripts/build-component.sh",
    "chars": 1340,
    "preview": "#!/bin/bash\n\nset -ex\n\nDIR=`realpath $(dirname \"${0}\")`\n\nBUILD_DIRECTORY=\"${SNAPCRAFT_PART_BUILD:-${DIR}/.build}\"\nINSTALL"
  },
  {
    "path": "build-scripts/components/README.md",
    "chars": 5666,
    "preview": "# Parts directory\n\nThis directory contains the build scripts for Go components built into MicroK8s.\n\nThe directory struc"
  },
  {
    "path": "build-scripts/components/cluster-agent/build.sh",
    "chars": 111,
    "preview": "#!/bin/bash\n\nexport INSTALL=\"${1}/bin\"\nmkdir -p \"${INSTALL}\"\n\nmake cluster-agent\ncp cluster-agent \"${INSTALL}\"\n"
  },
  {
    "path": "build-scripts/components/cluster-agent/repository",
    "chars": 52,
    "preview": "https://github.com/canonical/microk8s-cluster-agent\n"
  },
  {
    "path": "build-scripts/components/cluster-agent/version.sh",
    "chars": 25,
    "preview": "#!/bin/bash\n\necho \"main\"\n"
  },
  {
    "path": "build-scripts/components/cni/build.sh",
    "chars": 678,
    "preview": "#!/bin/bash\n\nVERSION=\"${2}\"\n\nINSTALL=\"${1}/opt/cni/bin\"\nmkdir -p \"${INSTALL}\"\n\n# these would very tedious to apply with "
  },
  {
    "path": "build-scripts/components/cni/patches/default/0001-single-entrypoint-for-cni-tools.patch",
    "chars": 2694,
    "preview": "From 3d0636d0ad86c9050da190b50bc01387d71dc80a Mon Sep 17 00:00:00 2001\nFrom: MicroK8s builder bot <microk8s-builder-bot@"
  },
  {
    "path": "build-scripts/components/cni/repository",
    "chars": 47,
    "preview": "https://github.com/containernetworking/plugins\n"
  },
  {
    "path": "build-scripts/components/cni/version.sh",
    "chars": 116,
    "preview": "#!/bin/bash\n\n# Match https://github.com/kubernetes/kubernetes/blob/master/build/dependencies.yaml#L20\necho \"v1.8.0\"\n"
  },
  {
    "path": "build-scripts/components/containerd/build.sh",
    "chars": 343,
    "preview": "#!/bin/bash\n\nINSTALL=\"${1}/bin\"\nmkdir -p \"${INSTALL}\"\n\nVERSION=\"${2}\"\nREVISION=$(git rev-parse HEAD)\n\nsed -i \"s,^VERSION"
  },
  {
    "path": "build-scripts/components/containerd/patches/default/0001-microk8s-sideload-images-plugin.patch",
    "chars": 4466,
    "preview": "From d703811ab64963a6d52e6ac98b6a33b26b13e020 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/containerd/patches/v2.1.3/0001-microk8s-sideload-images-plugin.patch",
    "chars": 4809,
    "preview": "From 7f26b3e013169510867383f09358b2d91641ad9f Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/containerd/repository",
    "chars": 41,
    "preview": "https://github.com/containerd/containerd\n"
  },
  {
    "path": "build-scripts/components/containerd/version.sh",
    "chars": 27,
    "preview": "#!/bin/bash\n\necho \"v2.1.3\"\n"
  },
  {
    "path": "build-scripts/components/etcd/build.sh",
    "chars": 180,
    "preview": "#!/bin/bash\n\nexport INSTALL=\"${1}\"\nmkdir -p \"${INSTALL}\"\n\nGO_LDFLAGS=\"-s -w\" GO_BUILD_FLAGS=\"-v\" make build\n\nfor bin in "
  },
  {
    "path": "build-scripts/components/etcd/repository",
    "chars": 32,
    "preview": "https://github.com/etcd-io/etcd\n"
  },
  {
    "path": "build-scripts/components/etcd/version.sh",
    "chars": 27,
    "preview": "#!/bin/bash\n\necho \"v3.6.6\"\n"
  },
  {
    "path": "build-scripts/components/flannel-cni-plugin/build.sh",
    "chars": 263,
    "preview": "#!/bin/bash\n\nINSTALL=\"${1}/opt/cni/bin\"\nmkdir -p \"${INSTALL}\"\n\nVERSION=\"${2}\"\n\nexport CGO_ENABLED=0\ngo build -o dist/fla"
  },
  {
    "path": "build-scripts/components/flannel-cni-plugin/repository",
    "chars": 41,
    "preview": "https://github.com/flannel-io/cni-plugin\n"
  },
  {
    "path": "build-scripts/components/flannel-cni-plugin/version.sh",
    "chars": 36,
    "preview": "#!/bin/bash\n\necho \"v1.8.0-flannel2\"\n"
  },
  {
    "path": "build-scripts/components/flanneld/build.sh",
    "chars": 263,
    "preview": "#!/bin/bash\n\nINSTALL=\"${1}/opt/cni/bin\"\nmkdir -p \"${INSTALL}\"\n\nVERSION=\"${2}\"\n\nexport CGO_ENABLED=0\ngo build -o dist/fla"
  },
  {
    "path": "build-scripts/components/flanneld/patches/default/0001-disable-udp-backend.patch",
    "chars": 794,
    "preview": "From 45ec777a0d113089453eca7fd2f7cb195555c6c9 Mon Sep 17 00:00:00 2001\nFrom: MicroK8s builder bot <microk8s-builder-bot@"
  },
  {
    "path": "build-scripts/components/flanneld/repository",
    "chars": 38,
    "preview": "https://github.com/flannel-io/flannel\n"
  },
  {
    "path": "build-scripts/components/flanneld/version.sh",
    "chars": 28,
    "preview": "#!/bin/bash\n\necho \"v0.27.4\"\n"
  },
  {
    "path": "build-scripts/components/helm/build.sh",
    "chars": 785,
    "preview": "#!/bin/bash\n\nVERSION=\"${2}\"\n\nINSTALL=\"${1}\"\nmkdir -p \"${INSTALL}/bin\"\n\nmake VERSION=\"${VERSION}\"\ncp bin/helm \"${INSTALL}"
  },
  {
    "path": "build-scripts/components/helm/repository",
    "chars": 29,
    "preview": "https://github.com/helm/helm\n"
  },
  {
    "path": "build-scripts/components/helm/version.sh",
    "chars": 28,
    "preview": "#!/bin/bash\n\necho \"v3.19.2\"\n"
  },
  {
    "path": "build-scripts/components/k8s-dqlite/build.sh",
    "chars": 161,
    "preview": "#!/bin/bash\n\nINSTALL=\"${1}/bin\"\nmkdir -p \"${INSTALL}\"\n\nmake static -j\n\ncp bin/static/dqlite \"${INSTALL}/dqlite\"\ncp bin/s"
  },
  {
    "path": "build-scripts/components/k8s-dqlite/repository",
    "chars": 40,
    "preview": "https://github.com/canonical/k8s-dqlite\n"
  },
  {
    "path": "build-scripts/components/k8s-dqlite/version.sh",
    "chars": 27,
    "preview": "#!/bin/bash\n\necho \"v1.8.1\"\n"
  },
  {
    "path": "build-scripts/components/kubernetes/build.sh",
    "chars": 597,
    "preview": "#!/bin/bash -x\n\nINSTALL=\"${1}\"\n\nexport KUBE_GIT_VERSION_FILE=\"${PWD}/.version.sh\"\n\nfor app in kubectl kubelite; do\n  mak"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.27.0/0000-Kubelite-integration.patch",
    "chars": 15118,
    "preview": "From d0ae18d074db5ff361f363073f32b2f30c7a3686 Mon Sep 17 00:00:00 2001\nFrom: Konstantinos Tsakalozos <kos.tsakalozos@can"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.27.0/0001-Unix-socket-skip-validation-in-component-status.patch",
    "chars": 945,
    "preview": "From dd1db952eab13912a55207c81a2ac267909677ac Mon Sep 17 00:00:00 2001\nFrom: Konstantinos Tsakalozos <kos.tsakalozos@can"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.27.4/0000-Kubelite-integration.patch",
    "chars": 15101,
    "preview": "From 3162aa9df25819b60a3c0a3b044394639d55280c Mon Sep 17 00:00:00 2001\nFrom: Konstantinos Tsakalozos <kos.tsakalozos@can"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.28.0/0000-Kubelite-integration.patch",
    "chars": 15101,
    "preview": "From 3162aa9df25819b60a3c0a3b044394639d55280c Mon Sep 17 00:00:00 2001\nFrom: Konstantinos Tsakalozos <kos.tsakalozos@can"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.28.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch",
    "chars": 1084,
    "preview": "From 55f4864d816c8e7ca0ebb39571dc88dbdf05eff2 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.31.0/0000-Kubelite-integration.patch",
    "chars": 14994,
    "preview": "From d261b947963b9e808725a21e3d55e52c20826e22 Mon Sep 17 00:00:00 2001\nFrom: Konstantinos Tsakalozos <kos.tsakalozos@can"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.31.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch",
    "chars": 1084,
    "preview": "From 55f4864d816c8e7ca0ebb39571dc88dbdf05eff2 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.32.0/0000-Kubelite-integration.patch",
    "chars": 14884,
    "preview": "From 819b718ecfee8c4f6fb503d0dea80a43e86cdb6f Mon Sep 17 00:00:00 2001\nFrom: Konstantinos Tsakalozos <kos.tsakalozos@can"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.32.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch",
    "chars": 1084,
    "preview": "From 55f4864d816c8e7ca0ebb39571dc88dbdf05eff2 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.33.0/0000-Kubelite-integration.patch",
    "chars": 14947,
    "preview": "From aa3c3a427082e2a1ddd9f72790a8977efefee1cf Mon Sep 17 00:00:00 2001\nFrom: Konstantinos Tsakalozos <kos.tsakalozos@can"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.33.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch",
    "chars": 1092,
    "preview": "From beaeb73228b7e4a836b3bd5d73e49402279a47a6 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.34.0/0000-Kubelite-integration.patch",
    "chars": 17100,
    "preview": "From 241fc2a00be6fde3f7059ae61842cba44dff82a5 Mon Sep 17 00:00:00 2001\nFrom: Konstantinos Tsakalozos <kos.tsakalozos@can"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.34.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch",
    "chars": 1092,
    "preview": "From e2e2155d05b3ddd16640272bd1360425a3883c78 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.34.0/0002-fix-allow-node-to-get-endpointslices.patch",
    "chars": 1350,
    "preview": "From dea2abd80878be1eff519216c0bad5a0e35462ec Mon Sep 17 00:00:00 2001\nFrom: Mateo Florido <mateo.florido@canonical.com>"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.35.0/0000-Kubelite-integration.patch",
    "chars": 17046,
    "preview": "From afd6e0c5da37c3ae02c22c91ef898c1169e8d657 Mon Sep 17 00:00:00 2001\nFrom: Homayoon Alimohammadi <homayoonalimohammadi"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.35.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch",
    "chars": 1092,
    "preview": "From e2e2155d05b3ddd16640272bd1360425a3883c78 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/kubernetes/patches/v1.35.0/0002-fix-allow-node-to-get-endpointslices.patch",
    "chars": 1350,
    "preview": "From dea2abd80878be1eff519216c0bad5a0e35462ec Mon Sep 17 00:00:00 2001\nFrom: Mateo Florido <mateo.florido@canonical.com>"
  },
  {
    "path": "build-scripts/components/kubernetes/pre-patch.sh",
    "chars": 197,
    "preview": "#!/bin/bash -x\n\n# Ensure clean Kubernetes version\nKUBE_ROOT=\"${PWD}\"\nsource \"${KUBE_ROOT}/hack/lib/version.sh\"\nkube::ver"
  },
  {
    "path": "build-scripts/components/kubernetes/repository",
    "chars": 41,
    "preview": "https://github.com/kubernetes/kubernetes\n"
  },
  {
    "path": "build-scripts/components/kubernetes/version.sh",
    "chars": 443,
    "preview": "#!/bin/bash\n\nKUBE_TRACK=\"${KUBE_TRACK:-}\"            # example: \"1.24\"\nKUBE_VERSION=\"${KUBE_VERSION:-}\"        # example"
  },
  {
    "path": "build-scripts/components/microk8s-completion/build.sh",
    "chars": 150,
    "preview": "#!/bin/bash\n\nINSTALL=\"${1}\"\n\ngo mod tidy -compat=1.17\ngo run -tags microk8s_hack ./cmd/helm 2> /dev/null\n\ncp microk8s.ba"
  },
  {
    "path": "build-scripts/components/microk8s-completion/patches/default/0001-microk8s-autocompleter-script.patch",
    "chars": 10941,
    "preview": "From 18e46f3fe5fdb6bb90c5c39b923c57d255733e1e Mon Sep 17 00:00:00 2001\nFrom: Homayoon Alimohammadi <homayoonalimohammadi"
  },
  {
    "path": "build-scripts/components/microk8s-completion/repository",
    "chars": 29,
    "preview": "https://github.com/helm/helm\n"
  },
  {
    "path": "build-scripts/components/microk8s-completion/version.sh",
    "chars": 28,
    "preview": "#!/bin/bash\n\necho \"v3.19.2\"\n"
  },
  {
    "path": "build-scripts/components/python/requirements.txt",
    "chars": 50,
    "preview": "PyYAML==6.0.1\nnetifaces==0.10.9\njsonschema==4.0.0\n"
  },
  {
    "path": "build-scripts/components/runc/build.sh",
    "chars": 289,
    "preview": "#!/bin/bash\n\nVERSION=\"${2}\"\n\nexport INSTALL=\"${1}/bin\"\nmkdir -p \"${INSTALL}\"\n\n# Ensure `runc --version` prints the corre"
  },
  {
    "path": "build-scripts/components/runc/patches/default/0001-Disable-static-PIE-on-arm64.patch",
    "chars": 923,
    "preview": "From 7b7171f0f5048225e0d914cbffd47295af1fbfc5 Mon Sep 17 00:00:00 2001\nFrom: Lucian Petrut <lpetrut@cloudbasesolutions.c"
  },
  {
    "path": "build-scripts/components/runc/repository",
    "chars": 39,
    "preview": "https://github.com/opencontainers/runc\n"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.1.12/0001-apparmor-change-profile-immediately-not-on-exec.patch",
    "chars": 1223,
    "preview": "From a367e391600dfab0d9eb3deaec4db300a2fb1fa1 Mon Sep 17 00:00:00 2001\nFrom: Alberto Mardegan <mardy@users.sourceforge.n"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.1.12/0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch",
    "chars": 1561,
    "preview": "From 5351ef6f5b592472e077512714b2516cdbae1b51 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.1.12/0003-standard_init_linux-change-AppArmor-profile-as-late-.patch",
    "chars": 2030,
    "preview": "From 103a94a51ea334d25bf573f2f20cd4d9a099d827 Mon Sep 17 00:00:00 2001\nFrom: Alberto Mardegan <mardy@users.sourceforge.n"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.1.15/0001-apparmor-change-profile-immediately-not-on-exec.patch",
    "chars": 1223,
    "preview": "From a367e391600dfab0d9eb3deaec4db300a2fb1fa1 Mon Sep 17 00:00:00 2001\nFrom: Alberto Mardegan <mardy@users.sourceforge.n"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.1.15/0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch",
    "chars": 1630,
    "preview": "From b145a4ac9e9cd09e82d35e0998c6ddee80854275 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.1.15/0003-standard_init_linux-change-AppArmor-profile-as-late-.patch",
    "chars": 2071,
    "preview": "From f9e0ca2f29c6c77ea9bc9c52929dac3915545dd9 Mon Sep 17 00:00:00 2001\nFrom: Alberto Mardegan <mardy@users.sourceforge.n"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.2.6/0001-apparmor-change-profile-immediately-not-on-exec.patch",
    "chars": 1229,
    "preview": "From 5cdb43bdc26e81be36d93fd8b81b7de6ad152c22 Mon Sep 17 00:00:00 2001\nFrom: Alberto Mardegan <mardy@users.sourceforge.n"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.2.6/0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch",
    "chars": 1612,
    "preview": "From 259ebdf71e84433f55c1b28efb206ccc3a1b2736 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.2.6/0003-standard_init_linux-change-AppArmor-profile-as-late-.patch",
    "chars": 2006,
    "preview": "From 3f82798f6081f060b244d7346524c2aced231287 Mon Sep 17 00:00:00 2001\nFrom: Alberto Mardegan <mardy@users.sourceforge.n"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.3.0/0001-apparmor-change-profile-immediately-not-on-exec.patch",
    "chars": 1229,
    "preview": "From 5cdb43bdc26e81be36d93fd8b81b7de6ad152c22 Mon Sep 17 00:00:00 2001\nFrom: Alberto Mardegan <mardy@users.sourceforge.n"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.3.0/0002-setns_init_linux-set-the-NNP-flag-after-changing-the.patch",
    "chars": 1612,
    "preview": "From 259ebdf71e84433f55c1b28efb206ccc3a1b2736 Mon Sep 17 00:00:00 2001\nFrom: Angelos Kolaitis <angelos.kolaitis@canonica"
  },
  {
    "path": "build-scripts/components/runc/strict-patches/v1.3.0/0003-standard_init_linux-change-AppArmor-profile-as-late-.patch",
    "chars": 1968,
    "preview": "From 7f91e445a8731856e2d22b2295d8438e07cf2bf7 Mon Sep 17 00:00:00 2001\nFrom: Alberto Mardegan <mardy@users.sourceforge.n"
  },
  {
    "path": "build-scripts/components/runc/version.sh",
    "chars": 27,
    "preview": "#!/bin/bash\n\necho \"v1.3.3\"\n"
  },
  {
    "path": "build-scripts/generate-bom.py",
    "chars": 3310,
    "preview": "#!/usr/bin/env python3\n\nimport json\nimport os\nfrom pathlib import Path\nimport subprocess\nimport sys\nimport yaml\n\nDIR = P"
  },
  {
    "path": "build-scripts/images.txt",
    "chars": 316,
    "preview": "docker.io/calico/cni:v3.29.3\ndocker.io/calico/kube-controllers:v3.29.3\ndocker.io/calico/node:v3.29.3\ndocker.io/cdkbot/ho"
  },
  {
    "path": "build-scripts/print-patches-for.py",
    "chars": 3770,
    "preview": "#!/usr/bin/env python3\n\nimport argparse\nimport os\nfrom pathlib import Path\n\nDIR = Path(__file__).absolute().parent\n\n# SN"
  },
  {
    "path": "build-scripts/update-images.sh",
    "chars": 1258,
    "preview": "#!/bin/bash -x\n\n## Description:\n#\n# Install MicroK8s from a specific channel and update the list of images required by M"
  },
  {
    "path": "docs/build.md",
    "chars": 6645,
    "preview": "# Building and testing MicroK8s\n\n## Building the snap from source\n\nTo build the MicroK8s snap, you need to install Snapc"
  },
  {
    "path": "docs/community.md",
    "chars": 4861,
    "preview": "# MicroK8s in the Wild\n\nPeople are doing amazing things with MicroK8s. Feel free to submit a pull\nrequest with updates t"
  },
  {
    "path": "docs/k8s-patches.md",
    "chars": 892,
    "preview": "# Patches for Kubernetes\n \nThe patch to add kubelite is applied on top of the Kubernetes source code during\nthe MicroK8s"
  },
  {
    "path": "installer/.gitignore",
    "chars": 41,
    "preview": ".venv/\nbin/\nlib/\nlib64\npyvenv.cfg\nshare/\n"
  },
  {
    "path": "installer/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "installer/build-linux.sh",
    "chars": 154,
    "preview": "#!/bin/bash\n\n\nvirtualenv -p python3 .venv\nsource ./.venv/bin/activate\npip install -r requirements.txt\npyinstaller ./micr"
  },
  {
    "path": "installer/cli/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "installer/cli/echo.py",
    "chars": 3680,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2017 Canonical Ltd\n#\n# This program is free s"
  },
  {
    "path": "installer/cli/microk8s.py",
    "chars": 13232,
    "preview": "import argparse\nimport logging\nimport traceback\nfrom typing import List\nfrom sys import exit, platform\nfrom os import ge"
  },
  {
    "path": "installer/common/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "installer/common/auxiliary.py",
    "chars": 5411,
    "preview": "import ctypes\nimport logging\nimport os\nimport psutil\nimport subprocess\n\nfrom abc import ABC\nfrom os.path import realpath"
  },
  {
    "path": "installer/common/definitions.py",
    "chars": 1401,
    "preview": "MAX_CHARACTERS_WRAP: int = 120\ncommand_descriptions = {\n    \"add-node\": \"Adds a node to a cluster\",\n    \"ambassador\": \"A"
  },
  {
    "path": "installer/common/errors.py",
    "chars": 512,
    "preview": "class BaseError(Exception):\n    \"\"\"Base class for all exceptions.\n\n    :cvar fmt: A format string that daughter classes "
  },
  {
    "path": "installer/common/file_utils.py",
    "chars": 2751,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2016-2019 Canonical Ltd\n#\n# This program is f"
  },
  {
    "path": "installer/microk8s.py",
    "chars": 739,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2020 Canonical Ltd\n#\n# This program is free s"
  },
  {
    "path": "installer/microk8s.spec",
    "chars": 847,
    "preview": "# -*- mode: python ; coding: utf-8 -*-\n\nimport PyInstaller.config\nPyInstaller.config.CONF['distpath'] = \"./\"\n\nblock_ciph"
  },
  {
    "path": "installer/requirements.txt",
    "chars": 328,
    "preview": "urllib3==1.26.19\nclick==7.1.2\nprogressbar33==2.4\npsutil==5.9.0\nrequests==2.32.2\nrequests_unixsocket==0.1.5\npysha3==1.0.2"
  },
  {
    "path": "installer/setup.cfg",
    "chars": 31,
    "preview": "[flake8]\nmax-line-length = 120\n"
  },
  {
    "path": "installer/setup.py",
    "chars": 778,
    "preview": "from setuptools import setup\n\nsetup(\n    name=\"microk8s\",\n    version=\"1.0.2\",\n    url=\"https://github.com/canonical/mic"
  },
  {
    "path": "installer/tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "installer/tests/integration/test_cli.py",
    "chars": 2207,
    "preview": "import os\nimport subprocess\nimport platform\nfrom unittest import mock\n\nimport pytest\nfrom click.testing import CliRunner"
  },
  {
    "path": "installer/tests/unit/test_auxiliary.py",
    "chars": 1265,
    "preview": "from common.auxiliary import Auxiliary\nfrom unittest.mock import Mock, patch\n\n\ndef get_mocked_args(disk=1, mem=1, cpu=1)"
  },
  {
    "path": "installer/tests/unit/test_cli.py",
    "chars": 829,
    "preview": "from cli.microk8s import install\nfrom unittest.mock import patch, MagicMock\nimport pytest\n\n\n@patch(\"common.auxiliary.Aux"
  },
  {
    "path": "installer/vm_providers/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "installer/vm_providers/_base_provider.py",
    "chars": 7434,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018-2019 Canonical Ltd\n#\n# This program is f"
  },
  {
    "path": "installer/vm_providers/_multipass/__init__.py",
    "chars": 778,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018 Canonical Ltd\n#\n# This program is free s"
  },
  {
    "path": "installer/vm_providers/_multipass/_instance_info.py",
    "chars": 3584,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018 Canonical Ltd\n#\n# This program is free s"
  },
  {
    "path": "installer/vm_providers/_multipass/_multipass.py",
    "chars": 6449,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018-2019 Canonical Ltd\n#\n# This program is f"
  },
  {
    "path": "installer/vm_providers/_multipass/_multipass_command.py",
    "chars": 13392,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018 Canonical Ltd\n#\n# This program is free s"
  },
  {
    "path": "installer/vm_providers/_multipass/_windows.py",
    "chars": 8514,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018 Canonical Ltd\n#\n# This program is free s"
  },
  {
    "path": "installer/vm_providers/errors.py",
    "chars": 9242,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018-2019 Canonical Ltd\n#\n# This program is f"
  },
  {
    "path": "installer/vm_providers/factory.py",
    "chars": 1139,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018 Canonical Ltd\n#\n# This program is free s"
  },
  {
    "path": "installer/vm_providers/repo/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "installer/vm_providers/repo/errors.py",
    "chars": 4940,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2015-2019 Canonical Ltd\n#\n# This program is f"
  },
  {
    "path": "installer/vm_providers/repo/snaps.py",
    "chars": 14506,
    "preview": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2017-2019 Canonical Ltd\n#\n# This program is f"
  },
  {
    "path": "installer/windows/README.md",
    "chars": 588,
    "preview": "# MicroK8s Installer\n\n## Windows\nUses the NSIS package to create the installer.  \n\n### Prerequisites\n\n* Requires [NSIS 3"
  },
  {
    "path": "installer/windows/microk8s.nsi",
    "chars": 6855,
    "preview": "!include \"MUI2.nsh\"\n!include \"nsDialogs.nsh\"\n!include \"LogicLib.nsh\"\n!include \"Sections.nsh\"\n\n!define PRODUCT_NAME \"Micr"
  },
  {
    "path": "microk8s-resources/actions/common/utils.sh",
    "chars": 49460,
    "preview": "#!/usr/bin/env bash\n\nget_microk8s_group() {\n  if is_strict\n  then\n    echo \"snap_microk8s\"\n  else\n    echo \"microk8s\"\n  "
  },
  {
    "path": "microk8s-resources/basic_auth.csv",
    "chars": 62,
    "preview": "bOU1pQYT0Sjfyg6omGb4zzwmTHXH5Yrp,admin,admin,\"system:masters\"\n"
  },
  {
    "path": "microk8s-resources/certs/csr-dqlite.conf.template",
    "chars": 479,
    "preview": "[ req ]\ndefault_bits = 2048\nprompt = no\ndefault_md = sha256\nreq_extensions = req_ext\ndistinguished_name = dn\n\n[ dn ]\nC ="
  },
  {
    "path": "microk8s-resources/certs/csr.conf.template",
    "chars": 665,
    "preview": "[ req ]\ndefault_bits = 2048\nprompt = no\ndefault_md = sha256\nreq_extensions = req_ext\ndistinguished_name = dn\n\n[ dn ]\nC ="
  },
  {
    "path": "microk8s-resources/client-x509.config.template",
    "chars": 367,
    "preview": "apiVersion: v1\nclusters:\n- cluster:\n    certificate-authority-data: CADATA\n    server: https://127.0.0.1:16443\n  name: m"
  },
  {
    "path": "microk8s-resources/client.config",
    "chars": 283,
    "preview": "apiVersion: v1\nclusters:\n- cluster:\n    server: http://127.0.0.1:8080\n  name: microk8s-cluster\ncontexts:\n- context:\n    "
  },
  {
    "path": "microk8s-resources/client.config.template",
    "chars": 344,
    "preview": "apiVersion: v1\nclusters:\n- cluster:\n    certificate-authority-data: CADATA\n    server: https://127.0.0.1:16443\n  name: m"
  },
  {
    "path": "microk8s-resources/containerd-profile",
    "chars": 1399,
    "preview": "#include <tunables/global>\n\n\nprofile cri-containerd.apparmor.d flags=(attach_disconnected,mediate_deleted) {\n\n  #include"
  },
  {
    "path": "microk8s-resources/default-args/admission-control-config-file.yaml",
    "chars": 129,
    "preview": "apiVersion: apiserver.config.k8s.io/v1\nkind: AdmissionConfiguration\nplugins:\n  - name: EventRateLimit\n    path: eventcon"
  },
  {
    "path": "microk8s-resources/default-args/apiserver-proxy",
    "chars": 132,
    "preview": "--traefik-config ${SNAP_DATA}/args/traefik/traefik.yaml\n--kubeconfig ${SNAP_DATA}/credentials/kubelet.config\n--refresh-i"
  },
  {
    "path": "microk8s-resources/default-args/certs.d/docker.io/hosts.toml",
    "chars": 106,
    "preview": "server = \"https://docker.io\"\n\n[host.\"https://registry-1.docker.io\"]\n  capabilities = [\"pull\", \"resolve\"]\n\n"
  },
  {
    "path": "microk8s-resources/default-args/certs.d/localhost__32000/hosts.toml",
    "chars": 105,
    "preview": "server = \"http://localhost:32000\"\n\n[host.\"http://localhost:32000\"]\n  capabilities = [\"pull\", \"resolve\"]\n\n"
  },
  {
    "path": "microk8s-resources/default-args/cluster-agent",
    "chars": 120,
    "preview": "--bind 0.0.0.0:25000\n--keyfile \"${SNAP_DATA}/certs/server.key\"\n--certfile \"${SNAP_DATA}/certs/server.crt\"\n--timeout 240\n"
  },
  {
    "path": "microk8s-resources/default-args/cni-env",
    "chars": 347,
    "preview": "# Choose CNI to deploy. Only 'calico' is supported at the moment\nCNI=calico\n\n# IPv4 configuration\nIPv4_SUPPORT=true\nIPv4"
  },
  {
    "path": "microk8s-resources/default-args/cni-network/flannel.conflist",
    "chars": 321,
    "preview": "{\n    \"name\": \"microk8s-flannel-network\",\n    \"plugins\": [\n      {\n        \"type\": \"flannel\",\n        \"delegate\": {\n    "
  },
  {
    "path": "microk8s-resources/default-args/containerd",
    "chars": 167,
    "preview": "--config ${SNAP_DATA}/args/containerd.toml\n--root ${SNAP_COMMON}/var/lib/containerd\n--state ${SNAP_COMMON}/run/container"
  },
  {
    "path": "microk8s-resources/default-args/containerd-env",
    "chars": 996,
    "preview": "# Remember to restart MicroK8s after editing this file:\n#\n# sudo microk8s stop; sudo microk8s start\n#\n\n# To start contai"
  },
  {
    "path": "microk8s-resources/default-args/containerd-template.toml",
    "chars": 2823,
    "preview": "# Use config version 2 to enable new configuration fields.\nversion = 2\noom_score = 0\n\n[grpc]\n  uid = 0\n  gid = 0\n  max_r"
  },
  {
    "path": "microk8s-resources/default-args/ctr",
    "chars": 64,
    "preview": "--address=${SNAP_COMMON}/run/containerd.sock\n--namespace k8s.io\n"
  },
  {
    "path": "microk8s-resources/default-args/etcd",
    "chars": 295,
    "preview": "--data-dir=${SNAP_COMMON}/var/run/etcd\n--advertise-client-urls=https://${DEFAULT_INTERFACE_IP_ADDR}:12379\n--listen-clien"
  },
  {
    "path": "microk8s-resources/default-args/eventconfig.yaml",
    "chars": 129,
    "preview": "apiVersion: eventratelimit.admission.k8s.io/v1alpha1\nkind: Configuration\nlimits:\n  - type: Server\n    qps: 5000\n    burs"
  },
  {
    "path": "microk8s-resources/default-args/flannel-network-mgr-config",
    "chars": 56,
    "preview": "{\"Network\": \"10.1.0.0/16\", \"Backend\": {\"Type\": \"vxlan\"}}"
  },
  {
    "path": "microk8s-resources/default-args/flannel-template.conflist",
    "chars": 502,
    "preview": "{\n    \"name\": \"microk8s-flannel-network\",\n    \"cniVersion\": \"0.3.1\",\n    \"plugins\": [\n      {\n        \"type\": \"flannel\","
  },
  {
    "path": "microk8s-resources/default-args/flanneld",
    "chars": 250,
    "preview": "--iface=\"\"\n--etcd-endpoints=https://127.0.0.1:12379\n--etcd-cafile=${SNAP_DATA}/certs/ca.crt\n--etcd-certfile=${SNAP_DATA}"
  },
  {
    "path": "microk8s-resources/default-args/git/.gitconfig",
    "chars": 132,
    "preview": "[safe]\n        directory = /snap/microk8s/current/addons/community/.git\n        directory = /snap/microk8s/current/addon"
  },
  {
    "path": "microk8s-resources/default-args/ha-conf",
    "chars": 17,
    "preview": "failure-domain=1\n"
  },
  {
    "path": "microk8s-resources/default-args/k8s-dqlite",
    "chars": 119,
    "preview": "--storage-dir=${SNAP_DATA}/var/kubernetes/backend/\n--listen=unix://${SNAP_DATA}/var/kubernetes/backend/kine.sock:12379\n"
  },
  {
    "path": "microk8s-resources/default-args/k8s-dqlite-env",
    "chars": 125,
    "preview": "# Environment variables k8s-dqlite will run with\n#\n# Enable dqlite debugging flags\n# LIBRAFT_TRACE=\"1\"\n# LIBDQLITE_TRACE"
  },
  {
    "path": "microk8s-resources/default-args/kube-apiserver",
    "chars": 2332,
    "preview": "--cert-dir=${SNAP_DATA}/certs\n--service-cluster-ip-range=10.152.183.0/24\n--authorization-mode=AlwaysAllow\n--service-acco"
  },
  {
    "path": "microk8s-resources/default-args/kube-controller-manager",
    "chars": 397,
    "preview": "--kubeconfig=${SNAP_DATA}/credentials/controller.config\n--service-account-private-key-file=${SNAP_DATA}/certs/serviceacc"
  },
  {
    "path": "microk8s-resources/default-args/kube-proxy",
    "chars": 129,
    "preview": "--kubeconfig=${SNAP_DATA}/credentials/proxy.config\n--cluster-cidr=10.1.0.0/16\n--healthz-bind-address=127.0.0.1\n--profili"
  },
  {
    "path": "microk8s-resources/default-args/kube-scheduler",
    "chars": 141,
    "preview": "--kubeconfig=${SNAP_DATA}/credentials/scheduler.config\n--leader-elect-lease-duration=60s\n--leader-elect-renew-deadline=3"
  },
  {
    "path": "microk8s-resources/default-args/kubectl",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "microk8s-resources/default-args/kubectl-env",
    "chars": 54,
    "preview": "export KUBECONFIG=$SNAP_DATA/credentials/client.config"
  },
  {
    "path": "microk8s-resources/default-args/kubelet",
    "chars": 913,
    "preview": "--kubeconfig=${SNAP_DATA}/credentials/kubelet.config\n--cert-dir=${SNAP_DATA}/certs\n--client-ca-file=${SNAP_DATA}/certs/c"
  },
  {
    "path": "microk8s-resources/default-args/kubelite",
    "chars": 348,
    "preview": "--scheduler-args-file=$SNAP_DATA/args/kube-scheduler\n--controller-manager-args-file=$SNAP_DATA/args/kube-controller-mana"
  },
  {
    "path": "microk8s-resources/default-args/traefik/provider-template.yaml",
    "chars": 319,
    "preview": "tcp:\n  routers:\n    Router-1:\n      rule: \"HostSNI(`*`)\"\n      service: \"kube-apiserver\"\n      tls:\n        passthrough:"
  },
  {
    "path": "microk8s-resources/default-args/traefik/traefik-template.yaml",
    "chars": 137,
    "preview": "entryPoints:\n  apiserver:\n    address: \":16443\"\nproviders:\n  file:\n    filename: ${SNAP_DATA}/args/traefik/provider.yaml"
  },
  {
    "path": "microk8s-resources/default-hooks/post-refresh.d/30-helm",
    "chars": 173,
    "preview": "#!/bin/bash\n\n# Install helm binaries in SNAP_DATA to maintain backwards-compatibility\nif [ -d \"${SNAP_DATA}/bin\" ]; then"
  },
  {
    "path": "microk8s-resources/default-hooks/reconcile.d/10-pods-restart",
    "chars": 411,
    "preview": "#!/bin/bash\n\n. \"${SNAP}/actions/common/utils.sh\"\n\nif ! [ -e \"${SNAP_DATA}/var/lock/no-cni-reload\" ] &&\n  [ -e \"${SNAP_DA"
  },
  {
    "path": "microk8s-resources/default-hooks/reconcile.d/90-calico-apply",
    "chars": 558,
    "preview": "#!/usr/bin/env bash\n\n. \"${SNAP}/actions/common/utils.sh\"\n\nuse_snap_env\n\nKUBECTL=\"${SNAP}/microk8s-kubectl.wrapper\"\n\nif ["
  },
  {
    "path": "microk8s-resources/default-hooks/remove.d/10-cni-link",
    "chars": 497,
    "preview": "#!/bin/bash\n\n. \"${SNAP}/actions/common/utils.sh\"\n\nif ! is_strict || (is_strict && snapctl is-connected network-control)\n"
  },
  {
    "path": "microk8s-resources/default-hooks/remove.d/10-cni-link-cilium",
    "chars": 294,
    "preview": "#!/bin/bash\n\n. \"${SNAP}/actions/common/utils.sh\"\n\nif ! is_strict || (is_strict && snapctl is-connected network-control)\n"
  },
  {
    "path": "microk8s-resources/default-hooks/remove.d/20-cni-netns",
    "chars": 268,
    "preview": "#!/bin/bash\n\n. \"${SNAP}/actions/common/utils.sh\"\n\nif ! is_strict || (is_strict && snapctl is-connected network-control)\n"
  },
  {
    "path": "microk8s-resources/default-hooks/remove.d/90-containers",
    "chars": 97,
    "preview": "#!/bin/bash\n\n. \"${SNAP}/actions/common/utils.sh\"\n\nremove_all_containers\nkill_all_container_shims\n"
  },
  {
    "path": "microk8s-resources/kubelet.config",
    "chars": 1924,
    "preview": "apiVersion: v1\nclusters:\n- cluster:\n    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURQakNDQWlh"
  },
  {
    "path": "microk8s-resources/kubelet.config.template",
    "chars": 319,
    "preview": "apiVersion: v1\nclusters:\n- cluster:\n    certificate-authority-data: CADATA\n    server: https://127.0.0.1:16443\n  name: m"
  },
  {
    "path": "microk8s-resources/kubeproxy.config",
    "chars": 1936,
    "preview": "apiVersion: v1\nclusters:\n- cluster:\n    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURQakNDQWlh"
  },
  {
    "path": "microk8s-resources/microk8s.default.yaml",
    "chars": 169,
    "preview": "# Default launch configuration for MicroK8s.\n---\nversion: 0.1.0\nextraKubeletArgs:\n  --cluster-domain: cluster.local\n  --"
  },
  {
    "path": "microk8s-resources/wrappers/apiservice-kicker",
    "chars": 3129,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nif [ -e ${SNAP_DATA}/var/lock/clustere"
  },
  {
    "path": "microk8s-resources/wrappers/git.wrapper",
    "chars": 262,
    "preview": "#!/usr/bin/env bash\n\n. $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nexport GIT_EXEC_PATH=\"$SNAP/usr/lib/git-core\"\nexport"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-add-node.wrapper",
    "chars": 1481,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nif [ -e ${SNAP_DATA}/var/lock/clustere"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-addons.wrapper",
    "chars": 172,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nexit_if_no_permissions\n\n${SNAP}/usr/bi"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-config.wrapper",
    "chars": 1464,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nif [ -e ${SNAP_DATA}/var/lock/clustere"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-ctr.wrapper",
    "chars": 356,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nexit_if_no_permissions\n\nexport CONTAIN"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-dashboard-proxy.wrapper",
    "chars": 190,
    "preview": "#!/usr/bin/env bash\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nexit_if_not_root\nexit_if_no_permissions"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-dbctl.wrapper",
    "chars": 189,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nexit_if_not_root\n\nexit_if_no_permissio"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-disable.wrapper",
    "chars": 301,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\n# avoid AppArmor denial in strict mode"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-enable.wrapper",
    "chars": 299,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\n# avoid AppArmor denial in strict mode"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-helm.wrapper",
    "chars": 345,
    "preview": "#!/usr/bin/env bash\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nif [ -e ${SNAP_DATA}/var/lock/clustered.lock ]\n"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-helm3.wrapper",
    "chars": 345,
    "preview": "#!/usr/bin/env bash\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nif [ -e ${SNAP_DATA}/var/lock/clustered.lock ]\n"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-images.wrapper",
    "chars": 172,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nexit_if_no_permissions\n\n${SNAP}/usr/bi"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-istioctl.wrapper",
    "chars": 712,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\n. $SNAP/actions/common/utils.sh\nuse_snap_env\n\nif [ ! -f \"${SNAP_DATA}/bin/istioctl\" ]; the"
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-join.wrapper",
    "chars": 335,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nif [ -d \"$SNAP_COMMON/default-storage\""
  },
  {
    "path": "microk8s-resources/wrappers/microk8s-kubectl.wrapper",
    "chars": 650,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nsource $SNAP/actions/common/utils.sh\n\nuse_snap_env\n\nif [ -e ${SNAP_DATA}/var/lock/clustere"
  }
]

// ... and 130 more files (download for full content)

About this extraction

This page contains the full source code of the canonical/microk8s GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 330 files (1.5 MB), approximately 373.0k tokens, and a symbol index with 617 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!