Full Code of nekomeowww/ollama-operator for AI

main ece318891898 cached
124 files
996.0 KB
230.0k tokens
156 symbols
1 requests
Download .txt
Showing preview only (1,052K chars total). Download the full file or copy to clipboard to get everything.
Repository: nekomeowww/ollama-operator
Branch: main
Commit: ece318891898
Files: 124
Total size: 996.0 KB

Directory structure:
gitextract_tcznvur4/

├── .dockerignore
├── .github/
│   ├── FUNDING.yml
│   ├── renovate.json
│   └── workflows/
│       ├── ci.yaml
│       ├── pr-docs-build.yaml
│       ├── pr-docs-deployment.yaml
│       ├── production-docs-deployment.yaml
│       ├── release-build.yml
│       └── unstable-build.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .krew.yaml
├── .tool-versions
├── .vscode/
│   └── settings.json
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── PROJECT
├── README.md
├── api/
│   └── ollama/
│       └── v1/
│           ├── groupversion_info.go
│           ├── model_types.go
│           └── zz_generated.deepcopy.go
├── cmd/
│   ├── kollama/
│   │   └── main.go
│   └── ollama-operator/
│       └── main.go
├── config/
│   ├── crd/
│   │   ├── bases/
│   │   │   └── ollama.ayaka.io_models.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── default/
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   └── manager_config_patch.yaml
│   ├── manager/
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── prometheus/
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac/
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── model_editor_role.yaml
│   │   ├── model_viewer_role.yaml
│   │   ├── role.yaml
│   │   ├── role_binding.yaml
│   │   └── service_account.yaml
│   └── samples/
│       ├── kustomization.yaml
│       └── ollama_v1_model.yaml
├── cspell.config.yaml
├── docs/
│   ├── .editorconfig
│   ├── .vitepress/
│   │   ├── config.mts
│   │   └── theme/
│   │       ├── components/
│   │       │   ├── GettingStartedBlocksEn.vue
│   │       │   ├── GettingStartedBlocksZhCn.vue
│   │       │   ├── TitleBlockContainer.vue
│   │       │   └── TitleBlockContainerGroup.vue
│   │       ├── index.mts
│   │       └── style.css
│   ├── eslint.config.js
│   ├── package.json
│   ├── pages/
│   │   ├── en/
│   │   │   ├── acknowledgements.md
│   │   │   ├── guide/
│   │   │   │   ├── getting-started/
│   │   │   │   │   ├── cli.md
│   │   │   │   │   ├── crd.md
│   │   │   │   │   └── index.md
│   │   │   │   ├── overview.md
│   │   │   │   └── supported-models.md
│   │   │   ├── index.md
│   │   │   ├── references/
│   │   │   │   ├── architectural-design.md
│   │   │   │   ├── cli/
│   │   │   │   │   ├── commands/
│   │   │   │   │   │   ├── deploy.md
│   │   │   │   │   │   ├── expose.md
│   │   │   │   │   │   └── undeploy.md
│   │   │   │   │   └── index.md
│   │   │   │   └── crd/
│   │   │   │       ├── index.md
│   │   │   │       └── model.md
│   │   │   └── snippets/
│   │   │       ├── deploy-kubernetes-cluster-with-kind.md
│   │   │       └── install-ollama-operator.md
│   │   └── zh-CN/
│   │       ├── acknowledgements.md
│   │       ├── guide/
│   │       │   ├── getting-started/
│   │       │   │   ├── cli.md
│   │       │   │   ├── crd.md
│   │       │   │   └── index.md
│   │       │   ├── overview.md
│   │       │   └── supported-models.md
│   │       ├── index.md
│   │       ├── references/
│   │       │   ├── architectural-design.md
│   │       │   ├── cli/
│   │       │   │   ├── commands/
│   │       │   │   │   ├── deploy.md
│   │       │   │   │   ├── expose.md
│   │       │   │   │   └── undeploy.md
│   │       │   │   └── index.md
│   │       │   └── crd/
│   │       │       ├── index.md
│   │       │       └── model.md
│   │       └── snippets/
│   │           ├── deploy-kubernetes-cluster-with-kind.md
│   │           └── install-ollama-operator.md
│   ├── public/
│   │   ├── _redirects
│   │   ├── browserconfig.xml
│   │   ├── demo-full.cast
│   │   ├── demo.cast
│   │   └── site.webmanifest
│   ├── shim.d.ts
│   ├── tsconfig.json
│   ├── uno.config.ts
│   └── vite.config.mts
├── go.mod
├── go.sum
├── hack/
│   ├── boilerplate.go.txt
│   ├── kind-config.yaml
│   ├── ollama-model-llama2-kind-cluster.yaml
│   ├── ollama-model-llama2-nfs.yaml
│   ├── ollama-model-phi-kind-cluster.yaml
│   └── ollama-model-phi-nfs.yaml
├── internal/
│   ├── cli/
│   │   └── kollama/
│   │       ├── cmd.go
│   │       ├── cmd_deploy.go
│   │       ├── cmd_expose.go
│   │       ├── cmd_undeploy.go
│   │       ├── common.go
│   │       └── wait_until.go
│   └── controller/
│       └── model_controller.go
└── pkg/
    ├── model/
    │   ├── image_store.go
    │   ├── model.go
    │   ├── model_test.go
    │   ├── pod.go
    │   ├── pod_test.go
    │   └── recorder.go
    └── operator/
        └── reconcile.go

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

================================================
FILE: .dockerignore
================================================
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Ignore build and test binaries.
bin/


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [nekomeowww]
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username
# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/renovate.json
================================================
{
    "$schema": "https://docs.renovatebot.com/renovate-schema.json",
    "automerge": true,
    "extends": [
      "config:recommended",
      ":dependencyDashboard",
      ":semanticPrefixFixDepsChoreOthers",
      ":prHourlyLimitNone",
      ":prConcurrentLimitNone",
      ":ignoreModulesAndTests",
      "schedule:weekly",
      "group:allNonMajor",
      "replacements:all",
      "workarounds:all"
    ]
  }


================================================
FILE: .github/workflows/ci.yaml
================================================
name: CI

on:
  push:
    paths-ignore:
      - 'docs/pages/**'
    branches:
      - main
  pull_request:
    paths-ignore:
      - 'docs/pages/**'
    branches:
      - main

env:
  STORE_PATH: ''

jobs:
  build_test:
    name: Build Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-go@v6
        with:
          go-version: "^1.25"
          cache: true

      - name: Test Build
        run: go build -v ./...

  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-go@v6
        with:
          go-version: "^1.25"
          cache: true

      - uses: actions/checkout@v6

      - name: golangci-lint
        uses: golangci/golangci-lint-action@v9.2.0
        with:
          args: --timeout=10m

  unittest:
    name: Unit Tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: "^1.25"
          cache: true

      - name: Unit tests
        run: |
          go test ./... -coverprofile=coverage.out -covermode=atomic
          go tool cover -func coverage.out


================================================
FILE: .github/workflows/pr-docs-build.yaml
================================================
name: Build PR Previewing Docs

on:
  pull_request:
    branches:
      - main
    paths:
      - 'docs/**'

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest]

    name: Build - ${{ matrix.os }}

    runs-on: ${{ matrix.os }}
    steps:
      # This is quite weird.
      # Even though this is the *intended* solution introduces in official blog post here
      # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
      # But still, as https://github.com/orgs/community/discussions/25220#discussioncomment-7856118 stated,
      # this is vulnerable since there is no source of truth about which PR in the triggered workflow.
      - name: Persist PR number
        run: |
          echo "${{ github.event.number }}" > pr_num

      - name: Persist branch name
        run: |
          echo "${{ github.head_ref }}" > branch_name

      - name: Upload PR artifact
        uses: actions/upload-artifact@v7
        with:
          name: pr-num
          path: ./pr_num
          overwrite: true

      - name: Upload PR artifact
        uses: actions/upload-artifact@v7
        with:
          name: branch-name
          path: ./branch_name
          overwrite: true
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - uses: pnpm/action-setup@v4
        with:
          run_install: false
          package_json_file: docs/package.json
      - uses: actions/setup-node@v6
        with:
          cache: pnpm
          node-version: latest
          registry-url: https://registry.npmjs.org
          cache-dependency-path: 'docs/pnpm-lock.yaml'
      - working-directory: docs
        run: pnpm install --frozen-lockfile

      - working-directory: docs
        run: pnpm docs:build
        env:
          # As suggested in Verbose Build option to be able to track down errors https://github.com/vuejs/vitepress/issues/422
          # vitepress build command does not have --debug option, so we need to set it manually where the debug package is used.
          # DEBUG: 'vitepress:*'
          VUE_PROD_HYDRATION_MISMATCH_DETAILS_FLAG: '1'

      - name: Upload artifact
        uses: actions/upload-artifact@v7
        with:
          name: docs-${{ matrix.os }}-build
          path: docs/.vitepress/dist
          overwrite: true


================================================
FILE: .github/workflows/pr-docs-deployment.yaml
================================================
name: Push PR Previewing Docs to Cloudflare Pages

on:
  workflow_run:
    workflows:
      - Build PR Previewing Docs
    types:
      - completed

env:
  PR_NUM: 0
  BRANCH_NAME: main

jobs:
  on-success:
    name: Deploy to Cloudflare Pages
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      - name: Download artifact - PR
        uses: dawidd6/action-download-artifact@v18
        with:
          workflow_conclusion: success
          run_id: ${{ github.event.workflow_run.id }}
          name: pr-num
          path: pr-num
          allow_forks: true

      - name: Download artifact - PR
        uses: dawidd6/action-download-artifact@v18
        with:
          workflow_conclusion: success
          run_id: ${{ github.event.workflow_run.id }}
          name: branch-name
          path: branch-name
          allow_forks: true

      - name: Obtain PR number
        id: pr-num
        run: |
          echo "PR_NUM=$(cat pr-num/pr_num)" >> $GITHUB_ENV

      - name: Obtain branch name
        id: branch-name
        run: |
          echo "BRANCH_NAME=$(cat branch-name/branch_name)" >> $GITHUB_ENV

      - name: Download artifact - Ubuntu
        uses: dawidd6/action-download-artifact@v18
        with:
          workflow_conclusion: success
          run_id: ${{ github.event.workflow_run.id }}
          name: docs-ubuntu-latest-build
          path: docs-ubuntu-latest-build
          allow_forks: true

      - name: Publish to Cloudflare Pages
        id: deploy
        uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          projectName: ${{ secrets.CLOUDFLARE_PROJECT_NAME }}
          directory: docs-ubuntu-latest-build
          # Optional: Switch what branch you are publishing to.
          # By default this will be the branch which triggered this workflow
          branch: ${{ env.BRANCH_NAME }}
          # Optional: Change the Wrangler version, allows you to point to a specific version or a tag such as `beta`
          wranglerVersion: '3'

      - name: Find Comment
        uses: peter-evans/find-comment@v4
        id: fc
        with:
          issue-number: ${{ env.PR_NUM }}
          comment-author: 'github-actions[bot]'
          body-includes: to Cloudflare Pages

      - name: Create or update comment
        uses: peter-evans/create-or-update-comment@v5
        with:
          comment-id: ${{ steps.fc.outputs.comment-id }}
          issue-number: ${{ env.PR_NUM }}
          body: |
            ## ✅ Successfully deployed to Cloudflare Pages

            | Status      | URL                                |
            |:------------|:-----------------------------------|
            | Success     | ${{ steps.deploy.outputs.url }}    |
          edit-mode: replace

  on-failure:
    name: Failed to build previewing docs
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write

    if: ${{ github.event.workflow_run.conclusion == 'failure' }}
    steps:
      - name: Download artifact - PR
        uses: dawidd6/action-download-artifact@v18
        with:
          workflow_conclusion: success
          run_id: ${{ github.event.workflow_run.id }}
          name: pr-num
          path: pr-num
          allow_forks: true

      - name: Obtain PR number
        id: pr-num
        run: |
          echo "PR_NUM=$(cat pr-num/pr_num)" >> $GITHUB_ENV

      - name: Find Comment
        uses: peter-evans/find-comment@v4
        id: fc
        with:
          issue-number: ${{ env.PR_NUM }}
          comment-author: 'github-actions[bot]'
          body-includes: to Cloudflare Pages

      - name: Create or update comment
        uses: peter-evans/create-or-update-comment@v5
        with:
          comment-id: ${{ steps.fc.outputs.comment-id }}
          issue-number: ${{ env.PR_NUM }}
          body: |
            ## ❌ Failed to deploy to Cloudflare Pages

            | Platform | Status      | URL                                                   |
            |:---------|:------------|:------------------------------------------------------|
            | Ubuntu   | Failed      | Please check the status and logs of the workflow run. |
            | Windows  | Failed      | Please check the status and logs of the workflow run. |
          edit-mode: replace


================================================
FILE: .github/workflows/production-docs-deployment.yaml
================================================
name: Build Docs to Cloudflare Pages

on:
  push:
    branches:
      - 'main'

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    environment:
      name: Production Docs
      url: https://ollama-operator.ayaka.io
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - uses: pnpm/action-setup@v4
        with:
          run_install: false
          package_json_file: docs/package.json
      - uses: actions/setup-node@v6
        with:
          cache: pnpm
          node-version: latest
          registry-url: https://registry.npmjs.org
          cache-dependency-path: 'docs/pnpm-lock.yaml'
      - working-directory: docs
        run: pnpm install --frozen-lockfile

      - working-directory: docs
        run: pnpm docs:build
        env:
          # As suggested in Verbose Build option to be able to track down errors https://github.com/vuejs/vitepress/issues/422
          # vitepress build command does not have --debug option, so we need to set it manually where the debug package is used.
          # DEBUG: 'vitepress:*'
          VUE_PROD_HYDRATION_MISMATCH_DETAILS_FLAG: '1'

      - name: Publish to Cloudflare Pages
        id: deploy
        uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          projectName: ${{ secrets.CLOUDFLARE_PROJECT_NAME }}
          directory: docs/.vitepress/dist
          # Optional: Switch what branch you are publishing to.
          # By default this will be the branch which triggered this workflow
          branch: main
          # Optional: Change the Wrangler version, allows you to point to a specific version or a tag such as `beta`
          wranglerVersion: '3'


================================================
FILE: .github/workflows/release-build.yml
================================================
name: Release Build

on:
  push:
    tags:
      - '**'
  workflow_dispatch:

jobs:
  goreleaser:
    name: kollama - Build for GitHub Releases
    permissions:
      contents: write
      packages: write
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: '1.26'
          cache: true

      - name: GoReleaser
        uses: goreleaser/goreleaser-action@v7
        with:
          version: latest
          args: release --clean --skip=validate
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Update new version in krew-index
        uses: rajatjindal/krew-release-bot@v0.0.51

  ghcr_build:
    name: ollama-operator - Build for ghcr.io
    permissions:
      packages: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Fetch version
        id: version
        run: |
          export LAST_TAGGED_COMMIT=$(git rev-list --tags --max-count=1)
          export LAST_TAG=$(git describe --tags $LAST_TAGGED_COMMIT)
          echo "version=${LAST_TAG#v}" >> $GITHUB_OUTPUT

      - # Add support for more platforms with QEMU (optional)
        # https://github.com/docker/setup-qemu-action
        name: Set up QEMU
        uses: docker/setup-qemu-action@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v4
        with:
          platforms: linux/amd64,linux/arm64

      - name: Sign in to GitHub Container Registry
        uses: docker/login-action@v4
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Create image tags
        id: dockerinfo
        run: |
          echo "taglatest=ghcr.io/${{ github.repository }}:latest" >> $GITHUB_OUTPUT
          echo "tag=ghcr.io/${{ github.repository }}:${{ steps.version.outputs.version }}" >> $GITHUB_OUTPUT

      - name: Build and Push
        uses: docker/build-push-action@v7
        with:
          platforms: linux/amd64,linux/arm64
          context: ./
          file: ./Dockerfile
          push: true
          no-cache: false
          tags: |
            ${{ steps.dockerinfo.outputs.taglatest }}
            ${{ steps.dockerinfo.outputs.tag }}

      - name: Build installer
        run: |
          make build-installer IMG=ghcr.io/${{ github.repository }}:${{ steps.version.outputs.version }}

      - name: Upload installer
        uses: actions/upload-artifact@v7
        with:
          name: ollama-operator-installer-${{ steps.version.outputs.version }}
          path: dist/install.yaml


================================================
FILE: .github/workflows/unstable-build.yml
================================================
name: Unstable Build

on:
  workflow_dispatch:

jobs:
  ghcr_build:
    name: Build for GitHub Container Registry
    permissions:
      packages: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - # Add support for more platforms with QEMU (optional)
        # https://github.com/docker/setup-qemu-action
        name: Set up QEMU
        uses: docker/setup-qemu-action@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v4
        with:
          platforms: linux/amd64,linux/arm64

      - name: Sign in to GitHub Container Registry
        uses: docker/login-action@v4
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Create image tags
        id: dockerinfo
        run: |
          echo "tagunstable=ghcr.io/${{ github.repository }}:unstable" >> $GITHUB_OUTPUT

      - name: Build and Push
        uses: docker/build-push-action@v7
        with:
          platforms: linux/amd64,linux/arm64
          context: ./
          file: ./Dockerfile
          push: true
          no-cache: false
          tags: |
            ${{ steps.dockerinfo.outputs.tagunstable }}

      - name: Build installer
        run: |
          make build-installer IMG=ghcr.io/${{ github.repository }}:unstable

      - name: Upload installer
        uses: actions/upload-artifact@v7
        with:
          name: ollama-operator-installer-unstable
          path: dist/install.yaml



================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin/*
Dockerfile.cross

# Built application files
!dist/install.yaml
dist/

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

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

# Go workspace file
go.work

# Kubernetes Generated files - skip generated files, except for vendored files
!vendor/**/zz_generated.*

# editor and IDE paraphernalia
.idea
!.vscode/settings.json
*.swp
*.swo
*~
.obsidian/

# Node.js related
.eslintcache
.npmrc
node_modules/

# Vite.js related
.temp
.vite-inspect

# Vitepress related
**/.vitepress/dist/
**/.vitepress/cache/

# Netlify related
**/.netlify/*
**/.netlify/functions-serve/*


================================================
FILE: .golangci.yml
================================================
version: "2"
run:
  allow-parallel-runners: true
linters:
  default: all
  disable:
    - containedctx
    - contextcheck
    - cyclop
    - depguard
    - err113
    - exhaustruct
    - funlen
    - gochecknoglobals
    - gochecknoinits
    - gocognit
    - gocyclo
    - godot
    - godox
    - ireturn
    - lll
    - maintidx
    - mnd
    - nilnil
    - nlreturn
    - paralleltest
    - tagalign
    - tagliatelle
    - testpackage
    - varnamelen
    - wrapcheck
    - noinlineerr
  settings:
    dupl:
      threshold: 1000
    gocritic:
      disabled-checks:
        - ifElseChain
    gosec:
      excludes:
        - G115
    mnd:
      ignored-files:
        - examples/.*
      ignored-functions:
        - context.WithTimeout
        - strconv.ParseComplex
    nestif:
      min-complexity: 9
    revive:
      rules:
        - name: blank-imports
          disabled: true
    wsl_v5:
      allow-first-in-block: true
      allow-whole-block: false
      branch-max-lines: 2
      enable:
        - assign-expr
      disable:
        - append
        - decl
  exclusions:
    generated: lax
    presets:
      - comments
      - common-false-positives
      - legacy
      - std-error-handling
    rules:
      - linters:
          - perfsprint
        path: _test\.go
      - linters:
          - forbidigo
        path: internal\/cli\/.*\.go
      - path: (.+)\.go$
        text: if statements should only be cuddled with assignments
      - path: (.+)\.go$
        text: if statements should only be cuddled with assignments used in the if statement itself
      - path: (.+)\.go$
        text: assignments should only be cuddled with other assignments
      - path: (.+)\.go$
        text: declarations should never be cuddled
      - path: (.+)\.go$
        text: block should not end with a whitespace
    paths:
      - apis
      - api
      - third_party$
      - builtin$
      - examples$
formatters:
  enable:
    - gofmt
    - goimports
  exclusions:
    generated: lax
    paths:
      - apis
      - api
      - third_party$
      - builtin$
      - examples$


================================================
FILE: .goreleaser.yml
================================================
project_name: kollama
release:
  github:
    owner: nekomeowww
    name: ollama-operator
builds:
  - id: kollama
    goos:
    - linux
    - windows
    - darwin
    goarch:
    - arm64
    - amd64
    - "386"
    env:
      - CGO_ENABLED=0
      - GO111MODULE=on
    main: cmd/kollama/main.go
archives:
  - id: kollama
    builds:
    - kollama
    name_template: "{{ .ProjectName }}_{{ .Tag }}_{{ .Os }}_{{ .Arch }}"
    format_overrides:
    - goos: windows
      format: zip


================================================
FILE: .krew.yaml
================================================
apiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
  name: kollama
spec:
  version: {{ .TagName }}
  homepage: https://github.com/nekomeowww/ollama-operator
  platforms:
  - selector:
      matchLabels:
        os: darwin
        arch: amd64
    {{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_darwin_amd64.tar.gz" .TagName }}
    bin: kollama
  - selector:
      matchLabels:
        os: darwin
        arch: arm64
    {{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_darwin_arm64.tar.gz" .TagName }}
    bin: kollama
  - selector:
      matchLabels:
        os: linux
        arch: amd64
    {{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_linux_amd64.tar.gz" .TagName }}
    bin: kollama
  - selector:
      matchLabels:
        os: linux
        arch: arm64
    {{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_linux_arm64.tar.gz" .TagName }}
    bin: kollama
  - selector:
      matchLabels:
        os: windows
        arch: amd64
    {{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_windows_amd64.zip" .TagName }}
    bin: kollama.exe
  shortDescription: Interact with the Ollama Operator
  description: |
    Usage:
      kubectl kollama deploy llama2
      This plugin will help you to interact with the Ollama Operator to deploy any LLM (Llama Language Model) to your Kubernetes cluster.
      Read more documentation at: https://github.com/nekomeowww/ollama-operator


================================================
FILE: .tool-versions
================================================
golang 1.26.1
golangci-lint 2.11.3


================================================
FILE: .vscode/settings.json
================================================
{
    "editor.formatOnSave": false,
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": "explicit",
        "source.organizeImports": "never"
    },
    // The following is optional.
    // It's better to put under project setting `.vscode/settings.json`
    // to avoid conflicts with working with different eslint configs
    // that does not support all formats.
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        "typescript",
        "typescriptreact",
        "vue",
        "json",
        "jsonc",
    ],
}


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Ollama Operator

### Prerequisites

- `go` version `v1.24.0+`
- `docker` version `17.03+`.
- `kubectl` version `v1.11.3+`.
- Access to a Kubernetes `v1.11.3+` cluster (Either kind, minikube is suitable for local development).

## Development

### Develop with `kind`

We have pre-defined `kind` configurations in the `hack` directory to help you get started with the development environment.

> [!NOTE]
> Install kind if you haven't already. You can install it using the following command:
>
> ```shell
> go install sigs.k8s.io/kind@latest
> ```

To create a `kind` cluster with the configurations defined in `hack/kind-config.yaml`, run the following command:

```sh
kind create cluster --config hack/kind-config.yaml
```

### Test controller locally

#### Build and install CRD to local cluster

```shell
make manifests && make install
```

#### Run the controller locally

```shell
make run
```

#### Create a CRD to test the controller

```shell
kubectl apply -f hack/ollama-model-phi-kind-cluster.yaml
```

#### Verify the resources is reconciling

```shell
kubectl describe models
```

## Deployment

### To Deploy on the cluster

**Build and push your image to the location specified by `IMG`:**

```sh
make docker-build docker-push IMG=<some-registry>/ollama-operator:tag
```

> [!NOTE]
> This image ought to be published in the personal registry you specified.
> And it is required to have access to pull the image from the working environment.
> Make sure you have the proper permission to the registry if the above commands don’t work.

**Install the CRDs into the cluster:**

```sh
make install
```

**Deploy the Manager to the cluster with the image specified by `IMG`:**

```sh
make deploy IMG=<some-registry>/ollama-operator:tag
```

> [!NOTE]
> If you encounter RBAC errors, you may need to grant yourself cluster-admin
> privileges or be logged in as admin.

**Create instances of your solution**
You can apply the samples (examples) from the config/sample:

```sh
kubectl apply -k config/samples/
```

> [!NOTE]
> Ensure that the samples has default values to test it out.

### To Uninstall

**Delete the instances (CRs) from the cluster:**

```sh
kubectl delete -k config/samples/
```

**Delete the APIs(CRDs) from the cluster:**

```sh
make uninstall
```

**UnDeploy the controller from the cluster:**

```sh
make undeploy
```

> [!NOTE]
> Run `make help` for more information on all potential `make` targets

## Project Distribution

### Test your build locally

Developers should test their builds locally before pushing the changes to the repository.

#### Test the build of `kollama` locally

This reporsitory has been configured to build and release by using [GoReleaser](https://goreleaser.com/):

> [!NOTE]
> Install GoReleaser if you haven't already by going through the steps in [GoReleaser Install](https://goreleaser.com/install/)

```shell
goreleaser release --snapshot --clean
```

#### Test the build of `ollama-operator` locally

To build the image for `ollama-operator` locally, run the following command:

```shell
docker buildx build --platform linux/amd64,linux/arm64 .
```

#### Test the release of `kollama` to `krew` locally

Please replace `<Your Tag>` with the tag you want to release.

```shell
docker run -v $(pwd)/.krew.yaml:/tmp/template-file.yaml ghcr.io/rajatjindal/krew-release-bot:v0.0.46 krew-release-bot template --tag <Your Tag> --template-file /tmp/template-file.yaml
```

### Build and distribute the project

Following are the steps to build the installer and distribute this project to users.

1. Build the installer for the image built and published in the registry:

```sh
make build-installer IMG=<some-registry>/ollama-operator:tag
```

NOTE: The makefile target mentioned above generates an 'install.yaml'
file in the dist directory. This file contains all the resources built
with Kustomize, which are necessary to install this project without
its dependencies.

2. Using the installer

Users can just run `kubectl apply -f <URL for YAML BUNDLE>` to install the project, i.e.:

```sh
kubectl apply -f https://raw.githubusercontent.com/<org>/ollama-operator/<tag or branch>/dist/install.yaml
```


================================================
FILE: Dockerfile
================================================
# Build the manager binary
FROM golang:1.26 AS builder

ARG TARGETOS
ARG TARGETARCH

WORKDIR /workspace

# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum

# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY cmd/ cmd/
COPY api/ api/
COPY internal/ internal/
COPY pkg/ pkg/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN go env -w CGO_ENABLED=0
RUN go env -w GOOS=${TARGETOS:-linux}
RUN go env -w GOARCH=${TARGETARCH}

RUN go build -a -o manager cmd/ollama-operator/main.go
RUN go build -a -o kollama cmd/kollama/main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot

WORKDIR /

COPY --from=builder /workspace/manager .
COPY --from=builder /workspace/kollama .

USER 65532:65532

ENTRYPOINT ["/manager"]


================================================
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 [yyyy] [name of copyright owner]

   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: Makefile
================================================
# Image URL to use all building/pushing image targets
IMG ?= ghcr.io/nekomeowww/ollama-operator:0.10.7
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.32.0

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

# CONTAINER_TOOL defines the container tool to be used for building images.
# Be aware that the target commands are only tested with Docker which is
# scaffolded by default. However, you might want to replace it to use other
# tools. (i.e. podman)
CONTAINER_TOOL ?= docker

# Setting SHELL to bash allows bash commands to be executed by recipes.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec

.PHONY: all
all: build

##@ General

# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk command is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php

.PHONY: help
help: ## Display this help.
	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

##@ Development

.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
	$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
	$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

.PHONY: fmt
fmt: ## Run go fmt against code.
	go fmt ./...

.PHONY: vet
vet: ## Run go vet against code.
	go vet ./...

.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
	KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e  # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
	go test ./test/e2e/ -v -ginkgo.v

.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter & yamllint
	$(GOLANGCI_LINT) run

.PHONY: lint-fix
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
	$(GOLANGCI_LINT) run --fix

##@ Build

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
	go build -o bin/manager cmd/ollama-operator/main.go
	go build -o bin/kollama cmd/kollama/main.go

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
	go run ./cmd/ollama-operator/main.go

# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
	$(CONTAINER_TOOL) build -t ${IMG} .

.PHONY: docker-push
docker-push: ## Push docker image with the manager.
	$(CONTAINER_TOOL) push ${IMG}

# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
	# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
	sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
	- $(CONTAINER_TOOL) buildx create --name project-v3-builder
	$(CONTAINER_TOOL) buildx use project-v3-builder
	- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
	- $(CONTAINER_TOOL) buildx rm project-v3-builder
	rm Dockerfile.cross

.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
	mkdir -p dist
	cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
	$(KUSTOMIZE) build config/default > dist/install.yaml

##@ Deployment

ifndef ignore-not-found
  ignore-not-found = false
endif

.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
	$(KUSTOMIZE) build config/crd | $(KUBECTL) apply --server-side=true -f -

.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
	$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
	cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
	$(KUSTOMIZE) build config/default | $(KUBECTL) apply --server-side=true -f -

.PHONY: undeploy
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
	$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

##@ Dependencies

## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
	mkdir -p $(LOCALBIN)

## Tool Binaries
KUBECTL ?= kubectl
KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION)
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION)
ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION)
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION)

## Tool Versions
KUSTOMIZE_VERSION ?= v5.6.0
CONTROLLER_TOOLS_VERSION ?= v0.17.2
ENVTEST_VERSION ?= release-0.20
GOLANGCI_LINT_VERSION ?= v1.63.4

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
	$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
	$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))

.PHONY: envtest
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
	$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))

.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
	$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION})

# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary (ideally with version)
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f $(1) ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\
}
endef


================================================
FILE: PROJECT
================================================
# Code generated by tool. DO NOT EDIT.
# This file is used to track the info used to scaffold your project
# and allow the plugins properly work.
# More info: https://book.kubebuilder.io/reference/project-config.html
domain: ayaka.io
layout:
- go.kubebuilder.io/v4
projectName: ollama-operator
repo: github.com/nekomeowww/ollama-operator
resources:
- api:
    crdVersion: v1
    namespaced: true
  controller: true
  domain: ayaka.io
  group: ollama
  kind: Model
  path: github.com/nekomeowww/ollama-operator/api/v1
  version: v1
version: "3"


================================================
FILE: README.md
================================================
<div align="center">
  <img alt="ollama" height="200px" src="./docs/public/logo.png">
</div>

# Ollama Operator

[![Discord](https://dcbadge.vercel.app/api/server/ollama?style=flat&compact=true)](https://discord.gg/ollama)

> Yet another operator for running large language models on Kubernetes with ease. 🙀
>
> Powered by **[Ollama](https://github.com/ollama/ollama)**! 🐫

While [Ollama](https://github.com/ollama/ollama) is a powerful tool for running large language models locally, and the user experience of CLI is just the same as using Docker CLI, it's not possible yet to replicate the same user experience on Kubernetes, especially when it comes to running multiple models on the same cluster with loads of resources and configurations.

That's where the Ollama Operator kicks in:

- Install the operator on your Kubernetes cluster
- Apply the needed CRDs
- Create your models
- Wait for the models to be fetched and loaded, that's it!

Thanks to the great works of [llama.cpp](https://github.com/ggerganov/llama.cpp), **no more worries about Python environment, CUDA drivers.**

The journey to large language models, AIGC, localized agents, [🦜🔗 Langchain](https://www.langchain.com/) and more is just a few steps away!

## Features

- ✅ Abilities to run multiple models on the same cluster.
- ✅ Compatible with all Ollama models, APIs, and CLI.
- ✅ Able to run on [general Kubernetes clusters](https://kubernetes.io/), [K3s clusters](https://k3s.io/) (Respberry Pi, TrueNAS SCALE, etc.), [kind](https://kind.sigs.k8s.io/), [minikube](https://minikube.sigs.k8s.io/docs/), etc. You name it!
- ✅ Easy to install, uninstall, and upgrade.
- ✅ Pull image once, share across the entire node (just like normal images).
- ✅ Easy to expose with existing Kubernetes services, ingress, etc.
- ✅ Doesn't require any additional dependencies, just Kubernetes

## Getting started

### Install operator

```shell
kubectl apply \
  --server-side=true \
  -f https://raw.githubusercontent.com/nekomeowww/ollama-operator/v0.10.1/dist/install.yaml
```

### Wait for the operator to be ready

```shell
kubectl wait \
  -n ollama-operator-system \
  --for=jsonpath='{.status.readyReplicas}'=1 \
  deployment/ollama-operator-controller-manager
```

### Deploy a model

> [!NOTE]
> You can also use the `kollama` CLI natively shipped by Ollama Operator, and will be easier to interact with the operator.
>
> Install `kollama` CLI:
>
> ```shell
> go install github.com/nekomeowww/ollama-operator/cmd/kollama@latest
> ```
>
> Deploy a model can be done with the following command:
>
> ```shell
> kollama deploy phi --expose --node-port 30001
> ```
>
> More information can be found at [CLI](https://ollama-operator.ayaka.io/pages/en/guide/getting-started/cli.html)

> [!IMPORTANT]
> Working with `kind`?
>
> The default provisioned `StorageClass` in `kind` is `standard`, and will only work with `ReadWriteOnce` access mode, therefore if you would need to run the operator with `kind`, you should specify `persistentVolume` with `accessMode: ReadWriteOnce` in the `Model` CRD:
> ```yaml
> apiVersion: ollama.ayaka.io/v1
> kind: Model
> metadata:
>   name: phi
> spec:
>   image: phi
>   persistentVolume:
>     accessMode: ReadWriteOnce
> ```

Let's create a `Model` CR for the model `phi`:

```yaml
apiVersion: ollama.ayaka.io/v1
kind: Model
metadata:
  name: phi
spec:
  image: phi
```

Apply the `Model` CR to your Kubernetes cluster:

```shell
kubectl apply -f ollama-model-phi.yaml
```

Wait for the model to be ready:

```shell
kubectl wait --for=jsonpath='{.status.readyReplicas}'=1 deployment/ollama-model-phi
```

### Access the model

1. Ready! Now let's forward the ports to access the model:

```shell
kubectl port-forward svc/ollama-model-phi ollama
```

2. Interact with the model:

```shell
ollama run phi
```

### Full options

```yaml
apiVersion: ollama.ayaka.io/v1
kind: Model
metadata:
  name: phi
spec:
  # Scale the model to 2 replicas
  replicas: 2
  # Use the model image `phi`
  image: phi
  imagePullPolicy: IfNotPresent
  storageClassName: local-path
  # If you have your own PersistentVolumeClaim created
  persistentVolumeClaim: your-pvc
  # If you need to specify the access mode for the PersistentVolume
  persistentVolume:
    accessMode: ReadWriteOnce
```

## Supported models

Unlock the abilities to run the following models with the Ollama Operator over Kubernetes:

> [!TIP]
> By the power of [`Modelfile`](https://github.com/ollama/ollama/blob/main/docs/modelfile.md) backed by Ollama, you can create and bundle any of your own model. **As long as it's a GGUF formatted model.**
>
> Full list of available images can be found at [Ollama Library](https://ollama.com/library).

> [!WARNING]
> You should have at least 8 GB of RAM available on your node to run the 7B models, 16 GB to run the 13B models, and 32 GB to run the 33B models.

> [!WARNING]
> The actual size of downloaded large language models are huge by comparing to the size of general container images.
>
> 1. Fast and stable network connection is recommended to download the models.
> 2. Efficient storage is required to store the models if you want to run models larger than 13B.

## Architecture Overview

There are two major components that the Ollama Operator will create for:

1. **Model Inferencing Server**: The model inferencing server is a gRPC server that runs the model and serves the model's API. It is created as a `Deployment` in the Kubernetes cluster.
2. **Model Image Storage**: The model image storage is a `PersistentVolume` that stores the model image. It is created as a `StatefulSet` along with a `PersistentVolumeClaim` in the Kubernetes cluster.

> [!NOTE]
> The image that created by [`Modelfile`](https://github.com/ollama/ollama/blob/main/docs/modelfile.md) of Ollama is a valid OCI format image, however, due to the incompatible `contentType` value, and the overall structure of the `Modelfile` image to the general container image, it's not possible to run the model directly with the general container runtime. Therefore a standalone service/deployment of **Model Image Storage** is required to be persisted on the Kubernetes cluster in order to hold and cache the previously downloaded model image.

The detailed resources it creates, and the relationships between them are shown in the following diagram:

<picture>
  <source
    srcset="./docs/public/architecture-theme-night.png"
    media="(prefers-color-scheme: dark)"
  />
  <source
    srcset="./docs/public/architecture-theme-day.png"
    media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
  />
  <img src="./docs/public/architecture-theme-day.png" />
</picture>

## Contributing

- Refer to the [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
- More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)

## Acknowledgements

Gratefully thanks to the following projects and their authors, contributors:

- [Ollama](https://github.com/ollama/ollama)
- [llama.cpp](https://github.com/ggerganov/llama.cpp)
- [Kubebuilder](https://book.kubebuilder.io/introduction.html)

It is because of their hard work and contributions that this program exists.


================================================
FILE: api/ollama/v1/groupversion_info.go
================================================
/*
Copyright 2024.

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 v1 contains API Schema definitions for the ollama v1 API group
// +kubebuilder:object:generate=true
// +groupName=ollama.ayaka.io
package v1

import (
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
	// GroupVersion is group version used to register these objects
	GroupVersion = schema.GroupVersion{Group: "ollama.ayaka.io", Version: "v1"}

	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

	// AddToScheme adds the types in this group-version to the given scheme.
	AddToScheme = SchemeBuilder.AddToScheme
)


================================================
FILE: api/ollama/v1/model_types.go
================================================
/*
Copyright 2024.

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 v1

import (
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type ModelPersistentVolumeSpec struct {
	// accessModes contains all ways the volume can be mounted.
	// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes
	// +optional
	AccessMode *corev1.PersistentVolumeAccessMode `json:"accessMode,omitempty" protobuf:"bytes,1,opt,name=accessMode,casttype=PersistentVolumeAccessMode"`
}

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// ModelSpec defines the desired state of Model
type ModelSpec struct {
	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
	// Important: Run "make" to regenerate code after modifying this file

	// Number of desired pods. This is a pointer to distinguish between explicit
	// zero and not specified. Defaults to 1.
	// +optional
	Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,1,opt,name=replicas"`
	// Container image name.
	// More info: https://kubernetes.io/docs/concepts/containers/images
	// This field is optional to allow higher level config management to default or override
	// container images in workload controllers like Deployments and StatefulSets.
	Image string `json:"image" protobuf:"bytes,2,name=image"`
	// Image pull policy.
	// One of Always, Never, IfNotPresent.
	// Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
	// Cannot be updated.
	// More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
	// +optional
	ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty" protobuf:"bytes,3,opt,name=imagePullPolicy,casttype=PullPolicy"`
	// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
	// If specified, these secrets will be passed to individual puller implementations for them to use.
	// More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod
	// +optional
	// +patchMergeKey=name
	// +patchStrategy=merge
	ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,4,rep,name=imagePullSecrets"`
	// Compute Resources required by this container.
	// Cannot be updated.
	// More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
	// +optional
	Resources corev1.ResourceRequirements `json:"resources,omitempty" protobuf:"bytes,5,opt,name=resources"`
	// storageClassName is the name of StorageClass to which this persistent volume belongs. Empty value
	// means that this volume does not belong to any StorageClass.
	// +optional
	StorageClassName *string `json:"storageClassName,omitempty" protobuf:"bytes,6,opt,name=storageClassName"`
	// persistentVolumeClaimVolumeSource represents a reference to a
	// PersistentVolumeClaim in the same namespace.
	// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
	// +optional
	PersistentVolumeClaim *corev1.PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty" protobuf:"bytes,7,opt,name=persistentVolumeClaim"`
	// spec defines a specification of a persistent volume owned by the cluster.
	// Provisioned by an administrator.
	// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes
	// +optional
	PersistentVolume *ModelPersistentVolumeSpec `json:"persistentVolume,omitempty" protobuf:"bytes,8,opt,name=persistentVolume"`
	// RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used
	// to run this pod.  If no RuntimeClass resource matches the named class, the pod will not be run.
	// If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an
	// empty definition that uses the default runtime handler.
	// More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class
	// +optional
	RuntimeClassName *string `json:"runtimeClassName,omitempty" protobuf:"bytes,9,opt,name=runtimeClassName"`
	// List of sources to populate environment variables in the container.
	// The keys defined within a source must be a C_IDENTIFIER. All invalid keys
	// will be reported as an event when the container is starting. When a key exists in multiple
	// sources, the value associated with the last source will take precedence.
	// Values defined by an Env with a duplicate key will take precedence.
	// Cannot be updated.
	// +optional
	ExtraEnvFrom []corev1.EnvFromSource `json:"extraEnvFrom,omitempty" protobuf:"bytes,10,rep,name=extraEnvFrom"`
	// List of environment variables to set in the container.
	// Cannot be updated.
	// +optional
	// +patchMergeKey=name
	// +patchStrategy=merge
	Env []corev1.EnvVar `json:"extraEnv,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,11,rep,name=extraEnv"`
	// PodTemplateSpec describes the data a pod should have when created from a template
	// +optional
	PodTemplate *corev1.PodTemplateSpec `json:"podTemplate" protobuf:"bytes,12,opt,name=podTemplate"`
}

type ConditionType string

// These are valid condition statuses. "ConditionTrue" means a resource is in the condition.
// "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes
// can't decide if a resource is in the condition or not. In the future, we could add other
// intermediate conditions, e.g. ConditionDegraded.
const (
	ModelUnknown ConditionType = "Unknown"
	// Available means the deployment is available, ie. at least the minimum available
	// replicas required are up and running for at least minReadySeconds.
	ModelAvailable ConditionType = "Available"
	// Progressing means the deployment is progressing. Progress for a deployment is
	// considered when a new replica set is created or adopted, and when new pods scale
	// up or old pods scale down. Progress is not estimated for paused deployments or
	// when progressDeadlineSeconds is not specified.
	ModelProgressing ConditionType = "Progressing"
	// ReplicaFailure is added in a deployment when one of its pods fails to be created
	// or deleted.
	ModelReplicaFailure ConditionType = "ReplicaFailure"
)

type ModelStatusCondition struct {
	// Type of deployment condition.
	Type ConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=ConditionType"`
	// Status of the condition, one of True, False, Unknown.
	Status corev1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"`
	// The last time this condition was updated.
	LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,6,opt,name=lastUpdateTime"`
	// Last time the condition transitioned from one status to another.
	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,7,opt,name=lastTransitionTime"`
	// The reason for the condition's last transition.
	Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"`
	// A human readable message indicating details about the transition.
	Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
}

// ModelStatus defines the observed state of Model
type ModelStatus struct {
	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
	// Important: Run "make" to regenerate code after modifying this file

	// Total number of non-terminated pods targeted by this deployment (their labels match the selector).
	// +optional
	Replicas int32 `json:"replicas,omitempty" protobuf:"varint,2,opt,name=replicas"`

	// readyReplicas is the number of pods targeted by this Deployment with a Ready Condition.
	// +optional
	ReadyReplicas int32 `json:"readyReplicas,omitempty" protobuf:"varint,7,opt,name=readyReplicas"`

	// Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.
	// +optional
	AvailableReplicas int32 `json:"availableReplicas,omitempty" protobuf:"varint,4,opt,name=availableReplicas"`

	// Total number of unavailable pods targeted by this deployment. This is the total number of
	// pods that are still required for the deployment to have 100% available capacity. They may
	// either be pods that are running but not yet available or pods that still have not been created.
	// +optional
	UnavailableReplicas int32 `json:"unavailableReplicas,omitempty" protobuf:"varint,5,opt,name=unavailableReplicas"`

	// +kubebuilder:validation:Optional
	Conditions []ModelStatusCondition `json:"conditions,omitempty"`
}

// Model is the Schema for the models API
// +genclient
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Model",type=string,JSONPath=`.spec.image`
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[0].type`
type Model struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   ModelSpec   `json:"spec,omitempty"`
	Status ModelStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// ModelList contains a list of Model
type ModelList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []Model `json:"items"`
}

func init() {
	SchemeBuilder.Register(&Model{}, &ModelList{})
}


================================================
FILE: api/ollama/v1/zz_generated.deepcopy.go
================================================
//go:build !ignore_autogenerated

/*
Copyright 2024.

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.
*/

// Code generated by controller-gen. DO NOT EDIT.

package v1

import (
	corev1 "k8s.io/api/core/v1"
	runtime "k8s.io/apimachinery/pkg/runtime"
)

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Model) DeepCopyInto(out *Model) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
	in.Spec.DeepCopyInto(&out.Spec)
	in.Status.DeepCopyInto(&out.Status)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Model.
func (in *Model) DeepCopy() *Model {
	if in == nil {
		return nil
	}
	out := new(Model)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Model) DeepCopyObject() runtime.Object {
	if c := in.DeepCopy(); c != nil {
		return c
	}
	return nil
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelList) DeepCopyInto(out *ModelList) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ListMeta.DeepCopyInto(&out.ListMeta)
	if in.Items != nil {
		in, out := &in.Items, &out.Items
		*out = make([]Model, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelList.
func (in *ModelList) DeepCopy() *ModelList {
	if in == nil {
		return nil
	}
	out := new(ModelList)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ModelList) DeepCopyObject() runtime.Object {
	if c := in.DeepCopy(); c != nil {
		return c
	}
	return nil
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelPersistentVolumeSpec) DeepCopyInto(out *ModelPersistentVolumeSpec) {
	*out = *in
	if in.AccessMode != nil {
		in, out := &in.AccessMode, &out.AccessMode
		*out = new(corev1.PersistentVolumeAccessMode)
		**out = **in
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelPersistentVolumeSpec.
func (in *ModelPersistentVolumeSpec) DeepCopy() *ModelPersistentVolumeSpec {
	if in == nil {
		return nil
	}
	out := new(ModelPersistentVolumeSpec)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelSpec) DeepCopyInto(out *ModelSpec) {
	*out = *in
	if in.Replicas != nil {
		in, out := &in.Replicas, &out.Replicas
		*out = new(int32)
		**out = **in
	}
	if in.ImagePullSecrets != nil {
		in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
		*out = make([]corev1.LocalObjectReference, len(*in))
		copy(*out, *in)
	}
	in.Resources.DeepCopyInto(&out.Resources)
	if in.StorageClassName != nil {
		in, out := &in.StorageClassName, &out.StorageClassName
		*out = new(string)
		**out = **in
	}
	if in.PersistentVolumeClaim != nil {
		in, out := &in.PersistentVolumeClaim, &out.PersistentVolumeClaim
		*out = new(corev1.PersistentVolumeClaimVolumeSource)
		**out = **in
	}
	if in.PersistentVolume != nil {
		in, out := &in.PersistentVolume, &out.PersistentVolume
		*out = new(ModelPersistentVolumeSpec)
		(*in).DeepCopyInto(*out)
	}
	if in.RuntimeClassName != nil {
		in, out := &in.RuntimeClassName, &out.RuntimeClassName
		*out = new(string)
		**out = **in
	}
	if in.ExtraEnvFrom != nil {
		in, out := &in.ExtraEnvFrom, &out.ExtraEnvFrom
		*out = make([]corev1.EnvFromSource, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
	if in.Env != nil {
		in, out := &in.Env, &out.Env
		*out = make([]corev1.EnvVar, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
	if in.PodTemplate != nil {
		in, out := &in.PodTemplate, &out.PodTemplate
		*out = new(corev1.PodTemplateSpec)
		(*in).DeepCopyInto(*out)
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelSpec.
func (in *ModelSpec) DeepCopy() *ModelSpec {
	if in == nil {
		return nil
	}
	out := new(ModelSpec)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelStatus) DeepCopyInto(out *ModelStatus) {
	*out = *in
	if in.Conditions != nil {
		in, out := &in.Conditions, &out.Conditions
		*out = make([]ModelStatusCondition, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelStatus.
func (in *ModelStatus) DeepCopy() *ModelStatus {
	if in == nil {
		return nil
	}
	out := new(ModelStatus)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelStatusCondition) DeepCopyInto(out *ModelStatusCondition) {
	*out = *in
	in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
	in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelStatusCondition.
func (in *ModelStatusCondition) DeepCopy() *ModelStatusCondition {
	if in == nil {
		return nil
	}
	out := new(ModelStatusCondition)
	in.DeepCopyInto(out)
	return out
}


================================================
FILE: cmd/kollama/main.go
================================================
/*
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 main

import (
	"os"

	"github.com/spf13/pflag"

	"github.com/nekomeowww/ollama-operator/internal/cli/kollama"
	"k8s.io/cli-runtime/pkg/genericiooptions"

	// Import authentication plugins (Go)
	// By default, plugins that use client-go cannot authenticate to Kubernetes clusters on many cloud providers. To address this, include the following import in your plugin:
	// from - Best practices · Krew
	// https://krew.sigs.k8s.io/docs/developer-guide/develop/best-practices/
	_ "k8s.io/client-go/plugin/pkg/client/auth"
)

func main() {
	flags := pflag.NewFlagSet("kollama", pflag.ExitOnError)
	pflag.CommandLine = flags

	root := kollama.NewCmd(genericiooptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr})

	err := root.Execute()
	if err != nil {
		os.Exit(1)
	}
}


================================================
FILE: cmd/ollama-operator/main.go
================================================
/*
Copyright 2024.

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 main

import (
	"crypto/tls"
	"flag"
	"os"

	// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
	// to ensure that exec-entrypoint and run can make use of them.
	_ "k8s.io/client-go/plugin/pkg/client/auth"

	"k8s.io/apimachinery/pkg/runtime"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/healthz"
	"sigs.k8s.io/controller-runtime/pkg/log/zap"
	metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
	"sigs.k8s.io/controller-runtime/pkg/webhook"

	ollamav1 "github.com/nekomeowww/ollama-operator/api/ollama/v1"
	"github.com/nekomeowww/ollama-operator/internal/controller"
	//+kubebuilder:scaffold:imports
)

var (
	scheme   = runtime.NewScheme()
	setupLog = ctrl.Log.WithName("setup")
)

func init() {
	utilruntime.Must(clientgoscheme.AddToScheme(scheme))

	utilruntime.Must(ollamav1.AddToScheme(scheme))
	//+kubebuilder:scaffold:scheme
}

func main() {
	var (
		metricsAddr          string
		enableLeaderElection bool
		probeAddr            string
		secureMetrics        bool
		enableHTTP2          bool
	)

	flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
	flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
	flag.BoolVar(&enableLeaderElection, "leader-elect", false,
		"Enable leader election for controller manager. "+
			"Enabling this will ensure there is only one active controller manager.")
	flag.BoolVar(&secureMetrics, "metrics-secure", false,
		"If set the metrics endpoint is served securely")
	flag.BoolVar(&enableHTTP2, "enable-http2", false,
		"If set, HTTP/2 will be enabled for the metrics and webhook servers")

	opts := zap.Options{
		Development: true,
	}
	opts.BindFlags(flag.CommandLine)
	flag.Parse()

	ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

	// if the enable-http2 flag is false (the default), http/2 should be disabled
	// due to its vulnerabilities. More specifically, disabling http/2 will
	// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
	// Rapid Reset CVEs. For more information see:
	// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
	// - https://github.com/advisories/GHSA-4374-p667-p6c8
	disableHTTP2 := func(c *tls.Config) {
		setupLog.Info("disabling http/2")

		c.NextProtos = []string{"http/1.1"}
	}

	tlsOpts := []func(*tls.Config){}
	if !enableHTTP2 {
		tlsOpts = append(tlsOpts, disableHTTP2)
	}

	webhookServer := webhook.NewServer(webhook.Options{
		TLSOpts: tlsOpts,
	})

	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme: scheme,
		Metrics: metricsserver.Options{
			BindAddress:   metricsAddr,
			SecureServing: secureMetrics,
			TLSOpts:       tlsOpts,
		},
		WebhookServer:          webhookServer,
		HealthProbeBindAddress: probeAddr,
		LeaderElection:         enableLeaderElection,
		LeaderElectionID:       "300b498d.ayaka.io",
		// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
		// when the Manager ends. This requires the binary to immediately end when the
		// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
		// speeds up voluntary leader transitions as the new leader don't have to wait
		// LeaseDuration time first.
		//
		// In the default scaffold provided, the program ends immediately after
		// the manager stops, so would be fine to enable this option. However,
		// if you are doing or is intended to do any operation such as perform cleanups
		// after the manager stops then its usage might be unsafe.
		// LeaderElectionReleaseOnCancel: true,
	})
	if err != nil {
		setupLog.Error(err, "unable to start manager")
		os.Exit(1)
	}

	if err = (&controller.ModelReconciler{
		Client:   mgr.GetClient(),
		Scheme:   mgr.GetScheme(),
		Recorder: mgr.GetEventRecorderFor("ollama-model-controller"),
	}).SetupWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "Model")
		os.Exit(1)
	}
	//+kubebuilder:scaffold:builder

	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
		setupLog.Error(err, "unable to set up health check")
		os.Exit(1)
	}

	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
		setupLog.Error(err, "unable to set up ready check")
		os.Exit(1)
	}

	setupLog.Info("starting manager")

	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")
		os.Exit(1)
	}
}


================================================
FILE: config/crd/bases/ollama.ayaka.io_models.yaml
================================================
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.17.2
  name: models.ollama.ayaka.io
spec:
  group: ollama.ayaka.io
  names:
    kind: Model
    listKind: ModelList
    plural: models
    singular: model
  scope: Namespaced
  versions:
  - additionalPrinterColumns:
    - jsonPath: .spec.image
      name: Model
      type: string
    - jsonPath: .status.conditions[0].type
      name: Status
      type: string
    name: v1
    schema:
      openAPIV3Schema:
        description: Model is the Schema for the models API
        properties:
          apiVersion:
            description: |-
              APIVersion defines the versioned schema of this representation of an object.
              Servers should convert recognized schemas to the latest internal value, and
              may reject unrecognized values.
              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
            type: string
          kind:
            description: |-
              Kind is a string value representing the REST resource this object represents.
              Servers may infer this from the endpoint the client submits requests to.
              Cannot be updated.
              In CamelCase.
              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
            type: string
          metadata:
            type: object
          spec:
            description: ModelSpec defines the desired state of Model
            properties:
              extraEnv:
                description: |-
                  List of environment variables to set in the container.
                  Cannot be updated.
                items:
                  description: EnvVar represents an environment variable present in
                    a Container.
                  properties:
                    name:
                      description: |-
                        Name of the environment variable.
                        May consist of any printable ASCII characters except '='.
                      type: string
                    value:
                      description: |-
                        Variable references $(VAR_NAME) are expanded
                        using the previously defined environment variables in the container and
                        any service environment variables. If a variable cannot be resolved,
                        the reference in the input string will be unchanged. Double $$ are reduced
                        to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.
                        "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
                        Escaped references will never be expanded, regardless of whether the variable
                        exists or not.
                        Defaults to "".
                      type: string
                    valueFrom:
                      description: Source for the environment variable's value. Cannot
                        be used if value is not empty.
                      properties:
                        configMapKeyRef:
                          description: Selects a key of a ConfigMap.
                          properties:
                            key:
                              description: The key to select.
                              type: string
                            name:
                              default: ""
                              description: |-
                                Name of the referent.
                                This field is effectively required, but due to backwards compatibility is
                                allowed to be empty. Instances of this type with an empty value here are
                                almost certainly wrong.
                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                              type: string
                            optional:
                              description: Specify whether the ConfigMap or its key
                                must be defined
                              type: boolean
                          required:
                          - key
                          type: object
                          x-kubernetes-map-type: atomic
                        fieldRef:
                          description: |-
                            Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`,
                            spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
                          properties:
                            apiVersion:
                              description: Version of the schema the FieldPath is
                                written in terms of, defaults to "v1".
                              type: string
                            fieldPath:
                              description: Path of the field to select in the specified
                                API version.
                              type: string
                          required:
                          - fieldPath
                          type: object
                          x-kubernetes-map-type: atomic
                        fileKeyRef:
                          description: |-
                            FileKeyRef selects a key of the env file.
                            Requires the EnvFiles feature gate to be enabled.
                          properties:
                            key:
                              description: |-
                                The key within the env file. An invalid key will prevent the pod from starting.
                                The keys defined within a source may consist of any printable ASCII characters except '='.
                                During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
                              type: string
                            optional:
                              default: false
                              description: |-
                                Specify whether the file or its key must be defined. If the file or key
                                does not exist, then the env var is not published.
                                If optional is set to true and the specified key does not exist,
                                the environment variable will not be set in the Pod's containers.

                                If optional is set to false and the specified key does not exist,
                                an error will be returned during Pod creation.
                              type: boolean
                            path:
                              description: |-
                                The path within the volume from which to select the file.
                                Must be relative and may not contain the '..' path or start with '..'.
                              type: string
                            volumeName:
                              description: The name of the volume mount containing
                                the env file.
                              type: string
                          required:
                          - key
                          - path
                          - volumeName
                          type: object
                          x-kubernetes-map-type: atomic
                        resourceFieldRef:
                          description: |-
                            Selects a resource of the container: only resources limits and requests
                            (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
                          properties:
                            containerName:
                              description: 'Container name: required for volumes,
                                optional for env vars'
                              type: string
                            divisor:
                              anyOf:
                              - type: integer
                              - type: string
                              description: Specifies the output format of the exposed
                                resources, defaults to "1"
                              pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                              x-kubernetes-int-or-string: true
                            resource:
                              description: 'Required: resource to select'
                              type: string
                          required:
                          - resource
                          type: object
                          x-kubernetes-map-type: atomic
                        secretKeyRef:
                          description: Selects a key of a secret in the pod's namespace
                          properties:
                            key:
                              description: The key of the secret to select from.  Must
                                be a valid secret key.
                              type: string
                            name:
                              default: ""
                              description: |-
                                Name of the referent.
                                This field is effectively required, but due to backwards compatibility is
                                allowed to be empty. Instances of this type with an empty value here are
                                almost certainly wrong.
                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                              type: string
                            optional:
                              description: Specify whether the Secret or its key must
                                be defined
                              type: boolean
                          required:
                          - key
                          type: object
                          x-kubernetes-map-type: atomic
                      type: object
                  required:
                  - name
                  type: object
                type: array
              extraEnvFrom:
                description: |-
                  List of sources to populate environment variables in the container.
                  The keys defined within a source must be a C_IDENTIFIER. All invalid keys
                  will be reported as an event when the container is starting. When a key exists in multiple
                  sources, the value associated with the last source will take precedence.
                  Values defined by an Env with a duplicate key will take precedence.
                  Cannot be updated.
                items:
                  description: EnvFromSource represents the source of a set of ConfigMaps
                    or Secrets
                  properties:
                    configMapRef:
                      description: The ConfigMap to select from
                      properties:
                        name:
                          default: ""
                          description: |-
                            Name of the referent.
                            This field is effectively required, but due to backwards compatibility is
                            allowed to be empty. Instances of this type with an empty value here are
                            almost certainly wrong.
                            More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                          type: string
                        optional:
                          description: Specify whether the ConfigMap must be defined
                          type: boolean
                      type: object
                      x-kubernetes-map-type: atomic
                    prefix:
                      description: |-
                        Optional text to prepend to the name of each environment variable.
                        May consist of any printable ASCII characters except '='.
                      type: string
                    secretRef:
                      description: The Secret to select from
                      properties:
                        name:
                          default: ""
                          description: |-
                            Name of the referent.
                            This field is effectively required, but due to backwards compatibility is
                            allowed to be empty. Instances of this type with an empty value here are
                            almost certainly wrong.
                            More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                          type: string
                        optional:
                          description: Specify whether the Secret must be defined
                          type: boolean
                      type: object
                      x-kubernetes-map-type: atomic
                  type: object
                type: array
              image:
                description: |-
                  Container image name.
                  More info: https://kubernetes.io/docs/concepts/containers/images
                  This field is optional to allow higher level config management to default or override
                  container images in workload controllers like Deployments and StatefulSets.
                type: string
              imagePullPolicy:
                description: |-
                  Image pull policy.
                  One of Always, Never, IfNotPresent.
                  Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
                  Cannot be updated.
                  More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
                type: string
              imagePullSecrets:
                description: |-
                  ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
                  If specified, these secrets will be passed to individual puller implementations for them to use.
                  More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod
                items:
                  description: |-
                    LocalObjectReference contains enough information to let you locate the
                    referenced object inside the same namespace.
                  properties:
                    name:
                      default: ""
                      description: |-
                        Name of the referent.
                        This field is effectively required, but due to backwards compatibility is
                        allowed to be empty. Instances of this type with an empty value here are
                        almost certainly wrong.
                        More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                      type: string
                  type: object
                  x-kubernetes-map-type: atomic
                type: array
              persistentVolume:
                description: |-
                  spec defines a specification of a persistent volume owned by the cluster.
                  Provisioned by an administrator.
                  More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes
                properties:
                  accessMode:
                    description: |-
                      accessModes contains all ways the volume can be mounted.
                      More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes
                    type: string
                type: object
              persistentVolumeClaim:
                description: |-
                  persistentVolumeClaimVolumeSource represents a reference to a
                  PersistentVolumeClaim in the same namespace.
                  More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
                properties:
                  claimName:
                    description: |-
                      claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume.
                      More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
                    type: string
                  readOnly:
                    description: |-
                      readOnly Will force the ReadOnly setting in VolumeMounts.
                      Default false.
                    type: boolean
                required:
                - claimName
                type: object
              podTemplate:
                description: PodTemplateSpec describes the data a pod should have
                  when created from a template
                properties:
                  metadata:
                    description: |-
                      Standard object's metadata.
                      More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
                    type: object
                  spec:
                    description: |-
                      Specification of the desired behavior of the pod.
                      More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
                    properties:
                      activeDeadlineSeconds:
                        description: |-
                          Optional duration in seconds the pod may be active on the node relative to
                          StartTime before the system will actively try to mark it failed and kill associated containers.
                          Value must be a positive integer.
                        format: int64
                        type: integer
                      affinity:
                        description: If specified, the pod's scheduling constraints
                        properties:
                          nodeAffinity:
                            description: Describes node affinity scheduling rules
                              for the pod.
                            properties:
                              preferredDuringSchedulingIgnoredDuringExecution:
                                description: |-
                                  The scheduler will prefer to schedule pods to nodes that satisfy
                                  the affinity expressions specified by this field, but it may choose
                                  a node that violates one or more of the expressions. The node that is
                                  most preferred is the one with the greatest sum of weights, i.e.
                                  for each node that meets all of the scheduling requirements (resource
                                  request, requiredDuringScheduling affinity expressions, etc.),
                                  compute a sum by iterating through the elements of this field and adding
                                  "weight" to the sum if the node matches the corresponding matchExpressions; the
                                  node(s) with the highest sum are the most preferred.
                                items:
                                  description: |-
                                    An empty preferred scheduling term matches all objects with implicit weight 0
                                    (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).
                                  properties:
                                    preference:
                                      description: A node selector term, associated
                                        with the corresponding weight.
                                      properties:
                                        matchExpressions:
                                          description: A list of node selector requirements
                                            by node's labels.
                                          items:
                                            description: |-
                                              A node selector requirement is a selector that contains values, a key, and an operator
                                              that relates the key and values.
                                            properties:
                                              key:
                                                description: The label key that the
                                                  selector applies to.
                                                type: string
                                              operator:
                                                description: |-
                                                  Represents a key's relationship to a set of values.
                                                  Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
                                                type: string
                                              values:
                                                description: |-
                                                  An array of string values. If the operator is In or NotIn,
                                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                  the values array must be empty. If the operator is Gt or Lt, the values
                                                  array must have a single element, which will be interpreted as an integer.
                                                  This array is replaced during a strategic merge patch.
                                                items:
                                                  type: string
                                                type: array
                                                x-kubernetes-list-type: atomic
                                            required:
                                            - key
                                            - operator
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        matchFields:
                                          description: A list of node selector requirements
                                            by node's fields.
                                          items:
                                            description: |-
                                              A node selector requirement is a selector that contains values, a key, and an operator
                                              that relates the key and values.
                                            properties:
                                              key:
                                                description: The label key that the
                                                  selector applies to.
                                                type: string
                                              operator:
                                                description: |-
                                                  Represents a key's relationship to a set of values.
                                                  Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
                                                type: string
                                              values:
                                                description: |-
                                                  An array of string values. If the operator is In or NotIn,
                                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                  the values array must be empty. If the operator is Gt or Lt, the values
                                                  array must have a single element, which will be interpreted as an integer.
                                                  This array is replaced during a strategic merge patch.
                                                items:
                                                  type: string
                                                type: array
                                                x-kubernetes-list-type: atomic
                                            required:
                                            - key
                                            - operator
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                      type: object
                                      x-kubernetes-map-type: atomic
                                    weight:
                                      description: Weight associated with matching
                                        the corresponding nodeSelectorTerm, in the
                                        range 1-100.
                                      format: int32
                                      type: integer
                                  required:
                                  - preference
                                  - weight
                                  type: object
                                type: array
                                x-kubernetes-list-type: atomic
                              requiredDuringSchedulingIgnoredDuringExecution:
                                description: |-
                                  If the affinity requirements specified by this field are not met at
                                  scheduling time, the pod will not be scheduled onto the node.
                                  If the affinity requirements specified by this field cease to be met
                                  at some point during pod execution (e.g. due to an update), the system
                                  may or may not try to eventually evict the pod from its node.
                                properties:
                                  nodeSelectorTerms:
                                    description: Required. A list of node selector
                                      terms. The terms are ORed.
                                    items:
                                      description: |-
                                        A null or empty node selector term matches no objects. The requirements of
                                        them are ANDed.
                                        The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
                                      properties:
                                        matchExpressions:
                                          description: A list of node selector requirements
                                            by node's labels.
                                          items:
                                            description: |-
                                              A node selector requirement is a selector that contains values, a key, and an operator
                                              that relates the key and values.
                                            properties:
                                              key:
                                                description: The label key that the
                                                  selector applies to.
                                                type: string
                                              operator:
                                                description: |-
                                                  Represents a key's relationship to a set of values.
                                                  Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
                                                type: string
                                              values:
                                                description: |-
                                                  An array of string values. If the operator is In or NotIn,
                                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                  the values array must be empty. If the operator is Gt or Lt, the values
                                                  array must have a single element, which will be interpreted as an integer.
                                                  This array is replaced during a strategic merge patch.
                                                items:
                                                  type: string
                                                type: array
                                                x-kubernetes-list-type: atomic
                                            required:
                                            - key
                                            - operator
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        matchFields:
                                          description: A list of node selector requirements
                                            by node's fields.
                                          items:
                                            description: |-
                                              A node selector requirement is a selector that contains values, a key, and an operator
                                              that relates the key and values.
                                            properties:
                                              key:
                                                description: The label key that the
                                                  selector applies to.
                                                type: string
                                              operator:
                                                description: |-
                                                  Represents a key's relationship to a set of values.
                                                  Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
                                                type: string
                                              values:
                                                description: |-
                                                  An array of string values. If the operator is In or NotIn,
                                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                  the values array must be empty. If the operator is Gt or Lt, the values
                                                  array must have a single element, which will be interpreted as an integer.
                                                  This array is replaced during a strategic merge patch.
                                                items:
                                                  type: string
                                                type: array
                                                x-kubernetes-list-type: atomic
                                            required:
                                            - key
                                            - operator
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                      type: object
                                      x-kubernetes-map-type: atomic
                                    type: array
                                    x-kubernetes-list-type: atomic
                                required:
                                - nodeSelectorTerms
                                type: object
                                x-kubernetes-map-type: atomic
                            type: object
                          podAffinity:
                            description: Describes pod affinity scheduling rules (e.g.
                              co-locate this pod in the same node, zone, etc. as some
                              other pod(s)).
                            properties:
                              preferredDuringSchedulingIgnoredDuringExecution:
                                description: |-
                                  The scheduler will prefer to schedule pods to nodes that satisfy
                                  the affinity expressions specified by this field, but it may choose
                                  a node that violates one or more of the expressions. The node that is
                                  most preferred is the one with the greatest sum of weights, i.e.
                                  for each node that meets all of the scheduling requirements (resource
                                  request, requiredDuringScheduling affinity expressions, etc.),
                                  compute a sum by iterating through the elements of this field and adding
                                  "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the
                                  node(s) with the highest sum are the most preferred.
                                items:
                                  description: The weights of all of the matched WeightedPodAffinityTerm
                                    fields are added per-node to find the most preferred
                                    node(s)
                                  properties:
                                    podAffinityTerm:
                                      description: Required. A pod affinity term,
                                        associated with the corresponding weight.
                                      properties:
                                        labelSelector:
                                          description: |-
                                            A label query over a set of resources, in this case pods.
                                            If it's null, this PodAffinityTerm matches with no Pods.
                                          properties:
                                            matchExpressions:
                                              description: matchExpressions is a list
                                                of label selector requirements. The
                                                requirements are ANDed.
                                              items:
                                                description: |-
                                                  A label selector requirement is a selector that contains values, a key, and an operator that
                                                  relates the key and values.
                                                properties:
                                                  key:
                                                    description: key is the label
                                                      key that the selector applies
                                                      to.
                                                    type: string
                                                  operator:
                                                    description: |-
                                                      operator represents a key's relationship to a set of values.
                                                      Valid operators are In, NotIn, Exists and DoesNotExist.
                                                    type: string
                                                  values:
                                                    description: |-
                                                      values is an array of string values. If the operator is In or NotIn,
                                                      the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                      the values array must be empty. This array is replaced during a strategic
                                                      merge patch.
                                                    items:
                                                      type: string
                                                    type: array
                                                    x-kubernetes-list-type: atomic
                                                required:
                                                - key
                                                - operator
                                                type: object
                                              type: array
                                              x-kubernetes-list-type: atomic
                                            matchLabels:
                                              additionalProperties:
                                                type: string
                                              description: |-
                                                matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
                                                map is equivalent to an element of matchExpressions, whose key field is "key", the
                                                operator is "In", and the values array contains only "value". The requirements are ANDed.
                                              type: object
                                          type: object
                                          x-kubernetes-map-type: atomic
                                        matchLabelKeys:
                                          description: |-
                                            MatchLabelKeys is a set of pod label keys to select which pods will
                                            be taken into consideration. The keys are used to lookup values from the
                                            incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
                                            to select the group of existing pods which pods will be taken into consideration
                                            for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
                                            pod labels will be ignored. The default value is empty.
                                            The same key is forbidden to exist in both matchLabelKeys and labelSelector.
                                            Also, matchLabelKeys cannot be set when labelSelector isn't set.
                                          items:
                                            type: string
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        mismatchLabelKeys:
                                          description: |-
                                            MismatchLabelKeys is a set of pod label keys to select which pods will
                                            be taken into consideration. The keys are used to lookup values from the
                                            incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
                                            to select the group of existing pods which pods will be taken into consideration
                                            for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
                                            pod labels will be ignored. The default value is empty.
                                            The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
                                            Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
                                          items:
                                            type: string
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        namespaceSelector:
                                          description: |-
                                            A label query over the set of namespaces that the term applies to.
                                            The term is applied to the union of the namespaces selected by this field
                                            and the ones listed in the namespaces field.
                                            null selector and null or empty namespaces list means "this pod's namespace".
                                            An empty selector ({}) matches all namespaces.
                                          properties:
                                            matchExpressions:
                                              description: matchExpressions is a list
                                                of label selector requirements. The
                                                requirements are ANDed.
                                              items:
                                                description: |-
                                                  A label selector requirement is a selector that contains values, a key, and an operator that
                                                  relates the key and values.
                                                properties:
                                                  key:
                                                    description: key is the label
                                                      key that the selector applies
                                                      to.
                                                    type: string
                                                  operator:
                                                    description: |-
                                                      operator represents a key's relationship to a set of values.
                                                      Valid operators are In, NotIn, Exists and DoesNotExist.
                                                    type: string
                                                  values:
                                                    description: |-
                                                      values is an array of string values. If the operator is In or NotIn,
                                                      the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                      the values array must be empty. This array is replaced during a strategic
                                                      merge patch.
                                                    items:
                                                      type: string
                                                    type: array
                                                    x-kubernetes-list-type: atomic
                                                required:
                                                - key
                                                - operator
                                                type: object
                                              type: array
                                              x-kubernetes-list-type: atomic
                                            matchLabels:
                                              additionalProperties:
                                                type: string
                                              description: |-
                                                matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
                                                map is equivalent to an element of matchExpressions, whose key field is "key", the
                                                operator is "In", and the values array contains only "value". The requirements are ANDed.
                                              type: object
                                          type: object
                                          x-kubernetes-map-type: atomic
                                        namespaces:
                                          description: |-
                                            namespaces specifies a static list of namespace names that the term applies to.
                                            The term is applied to the union of the namespaces listed in this field
                                            and the ones selected by namespaceSelector.
                                            null or empty namespaces list and null namespaceSelector means "this pod's namespace".
                                          items:
                                            type: string
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        topologyKey:
                                          description: |-
                                            This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
                                            the labelSelector in the specified namespaces, where co-located is defined as running on a node
                                            whose value of the label with key topologyKey matches that of any node on which any of the
                                            selected pods is running.
                                            Empty topologyKey is not allowed.
                                          type: string
                                      required:
                                      - topologyKey
                                      type: object
                                    weight:
                                      description: |-
                                        weight associated with matching the corresponding podAffinityTerm,
                                        in the range 1-100.
                                      format: int32
                                      type: integer
                                  required:
                                  - podAffinityTerm
                                  - weight
                                  type: object
                                type: array
                                x-kubernetes-list-type: atomic
                              requiredDuringSchedulingIgnoredDuringExecution:
                                description: |-
                                  If the affinity requirements specified by this field are not met at
                                  scheduling time, the pod will not be scheduled onto the node.
                                  If the affinity requirements specified by this field cease to be met
                                  at some point during pod execution (e.g. due to a pod label update), the
                                  system may or may not try to eventually evict the pod from its node.
                                  When there are multiple elements, the lists of nodes corresponding to each
                                  podAffinityTerm are intersected, i.e. all terms must be satisfied.
                                items:
                                  description: |-
                                    Defines a set of pods (namely those matching the labelSelector
                                    relative to the given namespace(s)) that this pod should be
                                    co-located (affinity) or not co-located (anti-affinity) with,
                                    where co-located is defined as running on a node whose value of
                                    the label with key <topologyKey> matches that of any node on which
                                    a pod of the set of pods is running
                                  properties:
                                    labelSelector:
                                      description: |-
                                        A label query over a set of resources, in this case pods.
                                        If it's null, this PodAffinityTerm matches with no Pods.
                                      properties:
                                        matchExpressions:
                                          description: matchExpressions is a list
                                            of label selector requirements. The requirements
                                            are ANDed.
                                          items:
                                            description: |-
                                              A label selector requirement is a selector that contains values, a key, and an operator that
                                              relates the key and values.
                                            properties:
                                              key:
                                                description: key is the label key
                                                  that the selector applies to.
                                                type: string
                                              operator:
                                                description: |-
                                                  operator represents a key's relationship to a set of values.
                                                  Valid operators are In, NotIn, Exists and DoesNotExist.
                                                type: string
                                              values:
                                                description: |-
                                                  values is an array of string values. If the operator is In or NotIn,
                                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                  the values array must be empty. This array is replaced during a strategic
                                                  merge patch.
                                                items:
                                                  type: string
                                                type: array
                                                x-kubernetes-list-type: atomic
                                            required:
                                            - key
                                            - operator
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        matchLabels:
                                          additionalProperties:
                                            type: string
                                          description: |-
                                            matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
                                            map is equivalent to an element of matchExpressions, whose key field is "key", the
                                            operator is "In", and the values array contains only "value". The requirements are ANDed.
                                          type: object
                                      type: object
                                      x-kubernetes-map-type: atomic
                                    matchLabelKeys:
                                      description: |-
                                        MatchLabelKeys is a set of pod label keys to select which pods will
                                        be taken into consideration. The keys are used to lookup values from the
                                        incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
                                        to select the group of existing pods which pods will be taken into consideration
                                        for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
                                        pod labels will be ignored. The default value is empty.
                                        The same key is forbidden to exist in both matchLabelKeys and labelSelector.
                                        Also, matchLabelKeys cannot be set when labelSelector isn't set.
                                      items:
                                        type: string
                                      type: array
                                      x-kubernetes-list-type: atomic
                                    mismatchLabelKeys:
                                      description: |-
                                        MismatchLabelKeys is a set of pod label keys to select which pods will
                                        be taken into consideration. The keys are used to lookup values from the
                                        incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
                                        to select the group of existing pods which pods will be taken into consideration
                                        for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
                                        pod labels will be ignored. The default value is empty.
                                        The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
                                        Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
                                      items:
                                        type: string
                                      type: array
                                      x-kubernetes-list-type: atomic
                                    namespaceSelector:
                                      description: |-
                                        A label query over the set of namespaces that the term applies to.
                                        The term is applied to the union of the namespaces selected by this field
                                        and the ones listed in the namespaces field.
                                        null selector and null or empty namespaces list means "this pod's namespace".
                                        An empty selector ({}) matches all namespaces.
                                      properties:
                                        matchExpressions:
                                          description: matchExpressions is a list
                                            of label selector requirements. The requirements
                                            are ANDed.
                                          items:
                                            description: |-
                                              A label selector requirement is a selector that contains values, a key, and an operator that
                                              relates the key and values.
                                            properties:
                                              key:
                                                description: key is the label key
                                                  that the selector applies to.
                                                type: string
                                              operator:
                                                description: |-
                                                  operator represents a key's relationship to a set of values.
                                                  Valid operators are In, NotIn, Exists and DoesNotExist.
                                                type: string
                                              values:
                                                description: |-
                                                  values is an array of string values. If the operator is In or NotIn,
                                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                  the values array must be empty. This array is replaced during a strategic
                                                  merge patch.
                                                items:
                                                  type: string
                                                type: array
                                                x-kubernetes-list-type: atomic
                                            required:
                                            - key
                                            - operator
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        matchLabels:
                                          additionalProperties:
                                            type: string
                                          description: |-
                                            matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
                                            map is equivalent to an element of matchExpressions, whose key field is "key", the
                                            operator is "In", and the values array contains only "value". The requirements are ANDed.
                                          type: object
                                      type: object
                                      x-kubernetes-map-type: atomic
                                    namespaces:
                                      description: |-
                                        namespaces specifies a static list of namespace names that the term applies to.
                                        The term is applied to the union of the namespaces listed in this field
                                        and the ones selected by namespaceSelector.
                                        null or empty namespaces list and null namespaceSelector means "this pod's namespace".
                                      items:
                                        type: string
                                      type: array
                                      x-kubernetes-list-type: atomic
                                    topologyKey:
                                      description: |-
                                        This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
                                        the labelSelector in the specified namespaces, where co-located is defined as running on a node
                                        whose value of the label with key topologyKey matches that of any node on which any of the
                                        selected pods is running.
                                        Empty topologyKey is not allowed.
                                      type: string
                                  required:
                                  - topologyKey
                                  type: object
                                type: array
                                x-kubernetes-list-type: atomic
                            type: object
                          podAntiAffinity:
                            description: Describes pod anti-affinity scheduling rules
                              (e.g. avoid putting this pod in the same node, zone,
                              etc. as some other pod(s)).
                            properties:
                              preferredDuringSchedulingIgnoredDuringExecution:
                                description: |-
                                  The scheduler will prefer to schedule pods to nodes that satisfy
                                  the anti-affinity expressions specified by this field, but it may choose
                                  a node that violates one or more of the expressions. The node that is
                                  most preferred is the one with the greatest sum of weights, i.e.
                                  for each node that meets all of the scheduling requirements (resource
                                  request, requiredDuringScheduling anti-affinity expressions, etc.),
                                  compute a sum by iterating through the elements of this field and subtracting
                                  "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
                                  node(s) with the highest sum are the most preferred.
                                items:
                                  description: The weights of all of the matched WeightedPodAffinityTerm
                                    fields are added per-node to find the most preferred
                                    node(s)
                                  properties:
                                    podAffinityTerm:
                                      description: Required. A pod affinity term,
                                        associated with the corresponding weight.
                                      properties:
                                        labelSelector:
                                          description: |-
                                            A label query over a set of resources, in this case pods.
                                            If it's null, this PodAffinityTerm matches with no Pods.
                                          properties:
                                            matchExpressions:
                                              description: matchExpressions is a list
                                                of label selector requirements. The
                                                requirements are ANDed.
                                              items:
                                                description: |-
                                                  A label selector requirement is a selector that contains values, a key, and an operator that
                                                  relates the key and values.
                                                properties:
                                                  key:
                                                    description: key is the label
                                                      key that the selector applies
                                                      to.
                                                    type: string
                                                  operator:
                                                    description: |-
                                                      operator represents a key's relationship to a set of values.
                                                      Valid operators are In, NotIn, Exists and DoesNotExist.
                                                    type: string
                                                  values:
                                                    description: |-
                                                      values is an array of string values. If the operator is In or NotIn,
                                                      the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                      the values array must be empty. This array is replaced during a strategic
                                                      merge patch.
                                                    items:
                                                      type: string
                                                    type: array
                                                    x-kubernetes-list-type: atomic
                                                required:
                                                - key
                                                - operator
                                                type: object
                                              type: array
                                              x-kubernetes-list-type: atomic
                                            matchLabels:
                                              additionalProperties:
                                                type: string
                                              description: |-
                                                matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
                                                map is equivalent to an element of matchExpressions, whose key field is "key", the
                                                operator is "In", and the values array contains only "value". The requirements are ANDed.
                                              type: object
                                          type: object
                                          x-kubernetes-map-type: atomic
                                        matchLabelKeys:
                                          description: |-
                                            MatchLabelKeys is a set of pod label keys to select which pods will
                                            be taken into consideration. The keys are used to lookup values from the
                                            incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
                                            to select the group of existing pods which pods will be taken into consideration
                                            for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
                                            pod labels will be ignored. The default value is empty.
                                            The same key is forbidden to exist in both matchLabelKeys and labelSelector.
                                            Also, matchLabelKeys cannot be set when labelSelector isn't set.
                                          items:
                                            type: string
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        mismatchLabelKeys:
                                          description: |-
                                            MismatchLabelKeys is a set of pod label keys to select which pods will
                                            be taken into consideration. The keys are used to lookup values from the
                                            incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
                                            to select the group of existing pods which pods will be taken into consideration
                                            for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
                                            pod labels will be ignored. The default value is empty.
                                            The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
                                            Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
                                          items:
                                            type: string
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        namespaceSelector:
                                          description: |-
                                            A label query over the set of namespaces that the term applies to.
                                            The term is applied to the union of the namespaces selected by this field
                                            and the ones listed in the namespaces field.
                                            null selector and null or empty namespaces list means "this pod's namespace".
                                            An empty selector ({}) matches all namespaces.
                                          properties:
                                            matchExpressions:
                                              description: matchExpressions is a list
                                                of label selector requirements. The
                                                requirements are ANDed.
                                              items:
                                                description: |-
                                                  A label selector requirement is a selector that contains values, a key, and an operator that
                                                  relates the key and values.
                                                properties:
                                                  key:
                                                    description: key is the label
                                                      key that the selector applies
                                                      to.
                                                    type: string
                                                  operator:
                                                    description: |-
                                                      operator represents a key's relationship to a set of values.
                                                      Valid operators are In, NotIn, Exists and DoesNotExist.
                                                    type: string
                                                  values:
                                                    description: |-
                                                      values is an array of string values. If the operator is In or NotIn,
                                                      the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                      the values array must be empty. This array is replaced during a strategic
                                                      merge patch.
                                                    items:
                                                      type: string
                                                    type: array
                                                    x-kubernetes-list-type: atomic
                                                required:
                                                - key
                                                - operator
                                                type: object
                                              type: array
                                              x-kubernetes-list-type: atomic
                                            matchLabels:
                                              additionalProperties:
                                                type: string
                                              description: |-
                                                matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
                                                map is equivalent to an element of matchExpressions, whose key field is "key", the
                                                operator is "In", and the values array contains only "value". The requirements are ANDed.
                                              type: object
                                          type: object
                                          x-kubernetes-map-type: atomic
                                        namespaces:
                                          description: |-
                                            namespaces specifies a static list of namespace names that the term applies to.
                                            The term is applied to the union of the namespaces listed in this field
                                            and the ones selected by namespaceSelector.
                                            null or empty namespaces list and null namespaceSelector means "this pod's namespace".
                                          items:
                                            type: string
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        topologyKey:
                                          description: |-
                                            This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
                                            the labelSelector in the specified namespaces, where co-located is defined as running on a node
                                            whose value of the label with key topologyKey matches that of any node on which any of the
                                            selected pods is running.
                                            Empty topologyKey is not allowed.
                                          type: string
                                      required:
                                      - topologyKey
                                      type: object
                                    weight:
                                      description: |-
                                        weight associated with matching the corresponding podAffinityTerm,
                                        in the range 1-100.
                                      format: int32
                                      type: integer
                                  required:
                                  - podAffinityTerm
                                  - weight
                                  type: object
                                type: array
                                x-kubernetes-list-type: atomic
                              requiredDuringSchedulingIgnoredDuringExecution:
                                description: |-
                                  If the anti-affinity requirements specified by this field are not met at
                                  scheduling time, the pod will not be scheduled onto the node.
                                  If the anti-affinity requirements specified by this field cease to be met
                                  at some point during pod execution (e.g. due to a pod label update), the
                                  system may or may not try to eventually evict the pod from its node.
                                  When there are multiple elements, the lists of nodes corresponding to each
                                  podAffinityTerm are intersected, i.e. all terms must be satisfied.
                                items:
                                  description: |-
                                    Defines a set of pods (namely those matching the labelSelector
                                    relative to the given namespace(s)) that this pod should be
                                    co-located (affinity) or not co-located (anti-affinity) with,
                                    where co-located is defined as running on a node whose value of
                                    the label with key <topologyKey> matches that of any node on which
                                    a pod of the set of pods is running
                                  properties:
                                    labelSelector:
                                      description: |-
                                        A label query over a set of resources, in this case pods.
                                        If it's null, this PodAffinityTerm matches with no Pods.
                                      properties:
                                        matchExpressions:
                                          description: matchExpressions is a list
                                            of label selector requirements. The requirements
                                            are ANDed.
                                          items:
                                            description: |-
                                              A label selector requirement is a selector that contains values, a key, and an operator that
                                              relates the key and values.
                                            properties:
                                              key:
                                                description: key is the label key
                                                  that the selector applies to.
                                                type: string
                                              operator:
                                                description: |-
                                                  operator represents a key's relationship to a set of values.
                                                  Valid operators are In, NotIn, Exists and DoesNotExist.
                                                type: string
                                              values:
                                                description: |-
                                                  values is an array of string values. If the operator is In or NotIn,
                                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                  the values array must be empty. This array is replaced during a strategic
                                                  merge patch.
                                                items:
                                                  type: string
                                                type: array
                                                x-kubernetes-list-type: atomic
                                            required:
                                            - key
                                            - operator
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        matchLabels:
                                          additionalProperties:
                                            type: string
                                          description: |-
                                            matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
                                            map is equivalent to an element of matchExpressions, whose key field is "key", the
                                            operator is "In", and the values array contains only "value". The requirements are ANDed.
                                          type: object
                                      type: object
                                      x-kubernetes-map-type: atomic
                                    matchLabelKeys:
                                      description: |-
                                        MatchLabelKeys is a set of pod label keys to select which pods will
                                        be taken into consideration. The keys are used to lookup values from the
                                        incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
                                        to select the group of existing pods which pods will be taken into consideration
                                        for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
                                        pod labels will be ignored. The default value is empty.
                                        The same key is forbidden to exist in both matchLabelKeys and labelSelector.
                                        Also, matchLabelKeys cannot be set when labelSelector isn't set.
                                      items:
                                        type: string
                                      type: array
                                      x-kubernetes-list-type: atomic
                                    mismatchLabelKeys:
                                      description: |-
                                        MismatchLabelKeys is a set of pod label keys to select which pods will
                                        be taken into consideration. The keys are used to lookup values from the
                                        incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
                                        to select the group of existing pods which pods will be taken into consideration
                                        for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
                                        pod labels will be ignored. The default value is empty.
                                        The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
                                        Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
                                      items:
                                        type: string
                                      type: array
                                      x-kubernetes-list-type: atomic
                                    namespaceSelector:
                                      description: |-
                                        A label query over the set of namespaces that the term applies to.
                                        The term is applied to the union of the namespaces selected by this field
                                        and the ones listed in the namespaces field.
                                        null selector and null or empty namespaces list means "this pod's namespace".
                                        An empty selector ({}) matches all namespaces.
                                      properties:
                                        matchExpressions:
                                          description: matchExpressions is a list
                                            of label selector requirements. The requirements
                                            are ANDed.
                                          items:
                                            description: |-
                                              A label selector requirement is a selector that contains values, a key, and an operator that
                                              relates the key and values.
                                            properties:
                                              key:
                                                description: key is the label key
                                                  that the selector applies to.
                                                type: string
                                              operator:
                                                description: |-
                                                  operator represents a key's relationship to a set of values.
                                                  Valid operators are In, NotIn, Exists and DoesNotExist.
                                                type: string
                                              values:
                                                description: |-
                                                  values is an array of string values. If the operator is In or NotIn,
                                                  the values array must be non-empty. If the operator is Exists or DoesNotExist,
                                                  the values array must be empty. This array is replaced during a strategic
                                                  merge patch.
                                                items:
                                                  type: string
                                                type: array
                                                x-kubernetes-list-type: atomic
                                            required:
                                            - key
                                            - operator
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        matchLabels:
                                          additionalProperties:
                                            type: string
                                          description: |-
                                            matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
                                            map is equivalent to an element of matchExpressions, whose key field is "key", the
                                            operator is "In", and the values array contains only "value". The requirements are ANDed.
                                          type: object
                                      type: object
                                      x-kubernetes-map-type: atomic
                                    namespaces:
                                      description: |-
                                        namespaces specifies a static list of namespace names that the term applies to.
                                        The term is applied to the union of the namespaces listed in this field
                                        and the ones selected by namespaceSelector.
                                        null or empty namespaces list and null namespaceSelector means "this pod's namespace".
                                      items:
                                        type: string
                                      type: array
                                      x-kubernetes-list-type: atomic
                                    topologyKey:
                                      description: |-
                                        This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
                                        the labelSelector in the specified namespaces, where co-located is defined as running on a node
                                        whose value of the label with key topologyKey matches that of any node on which any of the
                                        selected pods is running.
                                        Empty topologyKey is not allowed.
                                      type: string
                                  required:
                                  - topologyKey
                                  type: object
                                type: array
                                x-kubernetes-list-type: atomic
                            type: object
                        type: object
                      automountServiceAccountToken:
                        description: AutomountServiceAccountToken indicates whether
                          a service account token should be automatically mounted.
                        type: boolean
                      containers:
                        description: |-
                          List of containers belonging to the pod.
                          Containers cannot currently be added or removed.
                          There must be at least one container in a Pod.
                          Cannot be updated.
                        items:
                          description: A single application container that you want
                            to run within a pod.
                          properties:
                            args:
                              description: |-
                                Arguments to the entrypoint.
                                The container image's CMD is used if this is not provided.
                                Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
                                cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
                                to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
                                produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless
                                of whether the variable exists or not. Cannot be updated.
                                More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell
                              items:
                                type: string
                              type: array
                              x-kubernetes-list-type: atomic
                            command:
                              description: |-
                                Entrypoint array. Not executed within a shell.
                                The container image's ENTRYPOINT is used if this is not provided.
                                Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
                                cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
                                to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
                                produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless
                                of whether the variable exists or not. Cannot be updated.
                                More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell
                              items:
                                type: string
                              type: array
                              x-kubernetes-list-type: atomic
                            env:
                              description: |-
                                List of environment variables to set in the container.
                                Cannot be updated.
                              items:
                                description: EnvVar represents an environment variable
                                  present in a Container.
                                properties:
                                  name:
                                    description: |-
                                      Name of the environment variable.
                                      May consist of any printable ASCII characters except '='.
                                    type: string
                                  value:
                                    description: |-
                                      Variable references $(VAR_NAME) are expanded
                                      using the previously defined environment variables in the container and
                                      any service environment variables. If a variable cannot be resolved,
                                      the reference in the input string will be unchanged. Double $$ are reduced
                                      to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.
                                      "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
                                      Escaped references will never be expanded, regardless of whether the variable
                                      exists or not.
                                      Defaults to "".
                                    type: string
                                  valueFrom:
                                    description: Source for the environment variable's
                                      value. Cannot be used if value is not empty.
                                    properties:
                                      configMapKeyRef:
                                        description: Selects a key of a ConfigMap.
                                        properties:
                                          key:
                                            description: The key to select.
                                            type: string
                                          name:
                                            default: ""
                                            description: |-
                                              Name of the referent.
                                              This field is effectively required, but due to backwards compatibility is
                                              allowed to be empty. Instances of this type with an empty value here are
                                              almost certainly wrong.
                                              More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                            type: string
                                          optional:
                                            description: Specify whether the ConfigMap
                                              or its key must be defined
                                            type: boolean
                                        required:
                                        - key
                                        type: object
                                        x-kubernetes-map-type: atomic
                                      fieldRef:
                                        description: |-
                                          Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`,
                                          spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
                                        properties:
                                          apiVersion:
                                            description: Version of the schema the
                                              FieldPath is written in terms of, defaults
                                              to "v1".
                                            type: string
                                          fieldPath:
                                            description: Path of the field to select
                                              in the specified API version.
                                            type: string
                                        required:
                                        - fieldPath
                                        type: object
                                        x-kubernetes-map-type: atomic
                                      fileKeyRef:
                                        description: |-
                                          FileKeyRef selects a key of the env file.
                                          Requires the EnvFiles feature gate to be enabled.
                                        properties:
                                          key:
                                            description: |-
                                              The key within the env file. An invalid key will prevent the pod from starting.
                                              The keys defined within a source may consist of any printable ASCII characters except '='.
                                              During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
                                            type: string
                                          optional:
                                            default: false
                                            description: |-
                                              Specify whether the file or its key must be defined. If the file or key
                                              does not exist, then the env var is not published.
                                              If optional is set to true and the specified key does not exist,
                                              the environment variable will not be set in the Pod's containers.

                                              If optional is set to false and the specified key does not exist,
                                              an error will be returned during Pod creation.
                                            type: boolean
                                          path:
                                            description: |-
                                              The path within the volume from which to select the file.
                                              Must be relative and may not contain the '..' path or start with '..'.
                                            type: string
                                          volumeName:
                                            description: The name of the volume mount
                                              containing the env file.
                                            type: string
                                        required:
                                        - key
                                        - path
                                        - volumeName
                                        type: object
                                        x-kubernetes-map-type: atomic
                                      resourceFieldRef:
                                        description: |-
                                          Selects a resource of the container: only resources limits and requests
                                          (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
                                        properties:
                                          containerName:
                                            description: 'Container name: required
                                              for volumes, optional for env vars'
                                            type: string
                                          divisor:
                                            anyOf:
                                            - type: integer
                                            - type: string
                                            description: Specifies the output format
                                              of the exposed resources, defaults to
                                              "1"
                                            pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                                            x-kubernetes-int-or-string: true
                                          resource:
                                            description: 'Required: resource to select'
                                            type: string
                                        required:
                                        - resource
                                        type: object
                                        x-kubernetes-map-type: atomic
                                      secretKeyRef:
                                        description: Selects a key of a secret in
                                          the pod's namespace
                                        properties:
                                          key:
                                            description: The key of the secret to
                                              select from.  Must be a valid secret
                                              key.
                                            type: string
                                          name:
                                            default: ""
                                            description: |-
                                              Name of the referent.
                                              This field is effectively required, but due to backwards compatibility is
                                              allowed to be empty. Instances of this type with an empty value here are
                                              almost certainly wrong.
                                              More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                            type: string
                                          optional:
                                            description: Specify whether the Secret
                                              or its key must be defined
                                            type: boolean
                                        required:
                                        - key
                                        type: object
                                        x-kubernetes-map-type: atomic
                                    type: object
                                required:
                                - name
                                type: object
                              type: array
                              x-kubernetes-list-map-keys:
                              - name
                              x-kubernetes-list-type: map
                            envFrom:
                              description: |-
                                List of sources to populate environment variables in the container.
                                The keys defined within a source may consist of any printable ASCII characters except '='.
                                When a key exists in multiple
                                sources, the value associated with the last source will take precedence.
                                Values defined by an Env with a duplicate key will take precedence.
                                Cannot be updated.
                              items:
                                description: EnvFromSource represents the source of
                                  a set of ConfigMaps or Secrets
                                properties:
                                  configMapRef:
                                    description: The ConfigMap to select from
                                    properties:
                                      name:
                                        default: ""
                                        description: |-
                                          Name of the referent.
                                          This field is effectively required, but due to backwards compatibility is
                                          allowed to be empty. Instances of this type with an empty value here are
                                          almost certainly wrong.
                                          More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                        type: string
                                      optional:
                                        description: Specify whether the ConfigMap
                                          must be defined
                                        type: boolean
                                    type: object
                                    x-kubernetes-map-type: atomic
                                  prefix:
                                    description: |-
                                      Optional text to prepend to the name of each environment variable.
                                      May consist of any printable ASCII characters except '='.
                                    type: string
                                  secretRef:
                                    description: The Secret to select from
                                    properties:
                                      name:
                                        default: ""
                                        description: |-
                                          Name of the referent.
                                          This field is effectively required, but due to backwards compatibility is
                                          allowed to be empty. Instances of this type with an empty value here are
                                          almost certainly wrong.
                                          More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                                        type: string
                                      optional:
                                        description: Specify whether the Secret must
                                          be defined
                                        type: boolean
                                    type: object
                                    x-kubernetes-map-type: atomic
                                type: object
                              type: array
                              x-kubernetes-list-type: atomic
                            image:
                              description: |-
                                Container image name.
                                More info: https://kubernetes.io/docs/concepts/containers/images
                                This field is optional to allow higher level config management to default or override
                                container images in workload controllers like Deployments and StatefulSets.
                              type: string
                            imagePullPolicy:
                              description: |-
                                Image pull policy.
                                One of Always, Never, IfNotPresent.
                                Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
                                Cannot be updated.
                                More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
                              type: string
                            lifecycle:
                              description: |-
                                Actions that the management system should take in response to container lifecycle events.
                                Cannot be updated.
                              properties:
                                postStart:
                                  description: |-
                                    PostStart is called immediately after a container is created. If the handler fails,
                                    the container is terminated and restarted according to its restart policy.
                                    Other management of the container blocks until the hook completes.
                                    More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
                                  properties:
                                    exec:
                                      description: Exec specifies a command to execute
                                        in the container.
                                      properties:
                                        command:
                                          description: |-
                                            Command is the command line to execute inside the container, the working directory for the
                                            command  is root ('/') in the container's filesystem. The command is simply exec'd, it is
                                            not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
                                            a shell, you need to explicitly call out to that shell.
                                            Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
                                          items:
                                            type: string
                                          type: array
                                          x-kubernetes-list-type: atomic
                                      type: object
                                    httpGet:
                                      description: HTTPGet specifies an HTTP GET request
                                        to perform.
                                      properties:
                                        host:
                                          description: |-
                                            Host name to connect to, defaults to the pod IP. You probably want to set
                                            "Host" in httpHeaders instead.
                                          type: string
                                        httpHeaders:
                                          description: Custom headers to set in the
                                            request. HTTP allows repeated headers.
                                          items:
                                            description: HTTPHeader describes a custom
                                              header to be used in HTTP probes
                                            properties:
                                              name:
                                                description: |-
                                                  The header field name.
                                                  This will be canonicalized upon output, so case-variant names will be understood as the same header.
                                                type: string
                                              value:
                                                description: The header field value
                                                type: string
                                            required:
                                            - name
                                            - value
                                            type: object
                                          type: array
                                          x-kubernetes-list-type: atomic
                                        path:
                                          description: Path to access on the HTTP
                                            server.
                                          type: string
                                        port:
                                          anyOf:
                                          - type: integer
                                          - type: string
                                          description: |-
                                            Name or number of the port to access on the container.
                                            Number must be in the range 1 to 65535.
                                            Name must be an IANA_SVC_NAME.
                                          x-kubernetes-int-or-string: true
                                        scheme:
                                          description: |-
                                            Scheme to use for connecting to the host.
                                            Defaults to HTTP.
                                          type: string
                                      required:
                                      - port
                                      type: object
                                    sleep:
                                      description: Sleep represents a duration that
                                        the container should sleep.
                                      properties:
                                        seconds:
                                          description: Seconds is the number of seconds
                                            to sleep.
                                          format: int64
                                          type: integer
                                      required:
                                      - seconds
                                      type: object
                                    tcpSocket:
                                      description: |-
                                        Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept
                                        for backward compatibility. There is no validation of this field and
                                        lifecycle hooks will fail at runtime when it is specified.
                                      properties:
                                        host:
                                          description: 'Optional: Host name to connect
                                            to, defaults to the pod IP.'
                                          type: string
                                        port:
                                          anyOf:
                                          - type: integer
                                          - type: string
                                          description: |-
                                            Number or name of the port to access on the container.
                                            Number must be in the range 1 to 65535.
                                            Name must be an IANA_SVC_NAME.
                                          x-kubernetes-int-or-string: true
                                      required:
                                      - port
                                      type: object
                                  type: object
                                preStop:
                                  description: |-
                                    PreStop is called immediately before a container is terminated due to an
                                    API request or management event such as liveness/startup probe failure,
                                    preemption, resource contention, etc. The handler is not called if the
                                    container crashes or exits. The Pod's termination grace period countdown begins before the
                                    PreStop hook is executed. Regardless of the outcome of the handler, the
                                    container will eventually terminate within the Pod's termination grace
                 
Download .txt
gitextract_tcznvur4/

├── .dockerignore
├── .github/
│   ├── FUNDING.yml
│   ├── renovate.json
│   └── workflows/
│       ├── ci.yaml
│       ├── pr-docs-build.yaml
│       ├── pr-docs-deployment.yaml
│       ├── production-docs-deployment.yaml
│       ├── release-build.yml
│       └── unstable-build.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .krew.yaml
├── .tool-versions
├── .vscode/
│   └── settings.json
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── PROJECT
├── README.md
├── api/
│   └── ollama/
│       └── v1/
│           ├── groupversion_info.go
│           ├── model_types.go
│           └── zz_generated.deepcopy.go
├── cmd/
│   ├── kollama/
│   │   └── main.go
│   └── ollama-operator/
│       └── main.go
├── config/
│   ├── crd/
│   │   ├── bases/
│   │   │   └── ollama.ayaka.io_models.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── default/
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   └── manager_config_patch.yaml
│   ├── manager/
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── prometheus/
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac/
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── model_editor_role.yaml
│   │   ├── model_viewer_role.yaml
│   │   ├── role.yaml
│   │   ├── role_binding.yaml
│   │   └── service_account.yaml
│   └── samples/
│       ├── kustomization.yaml
│       └── ollama_v1_model.yaml
├── cspell.config.yaml
├── docs/
│   ├── .editorconfig
│   ├── .vitepress/
│   │   ├── config.mts
│   │   └── theme/
│   │       ├── components/
│   │       │   ├── GettingStartedBlocksEn.vue
│   │       │   ├── GettingStartedBlocksZhCn.vue
│   │       │   ├── TitleBlockContainer.vue
│   │       │   └── TitleBlockContainerGroup.vue
│   │       ├── index.mts
│   │       └── style.css
│   ├── eslint.config.js
│   ├── package.json
│   ├── pages/
│   │   ├── en/
│   │   │   ├── acknowledgements.md
│   │   │   ├── guide/
│   │   │   │   ├── getting-started/
│   │   │   │   │   ├── cli.md
│   │   │   │   │   ├── crd.md
│   │   │   │   │   └── index.md
│   │   │   │   ├── overview.md
│   │   │   │   └── supported-models.md
│   │   │   ├── index.md
│   │   │   ├── references/
│   │   │   │   ├── architectural-design.md
│   │   │   │   ├── cli/
│   │   │   │   │   ├── commands/
│   │   │   │   │   │   ├── deploy.md
│   │   │   │   │   │   ├── expose.md
│   │   │   │   │   │   └── undeploy.md
│   │   │   │   │   └── index.md
│   │   │   │   └── crd/
│   │   │   │       ├── index.md
│   │   │   │       └── model.md
│   │   │   └── snippets/
│   │   │       ├── deploy-kubernetes-cluster-with-kind.md
│   │   │       └── install-ollama-operator.md
│   │   └── zh-CN/
│   │       ├── acknowledgements.md
│   │       ├── guide/
│   │       │   ├── getting-started/
│   │       │   │   ├── cli.md
│   │       │   │   ├── crd.md
│   │       │   │   └── index.md
│   │       │   ├── overview.md
│   │       │   └── supported-models.md
│   │       ├── index.md
│   │       ├── references/
│   │       │   ├── architectural-design.md
│   │       │   ├── cli/
│   │       │   │   ├── commands/
│   │       │   │   │   ├── deploy.md
│   │       │   │   │   ├── expose.md
│   │       │   │   │   └── undeploy.md
│   │       │   │   └── index.md
│   │       │   └── crd/
│   │       │       ├── index.md
│   │       │       └── model.md
│   │       └── snippets/
│   │           ├── deploy-kubernetes-cluster-with-kind.md
│   │           └── install-ollama-operator.md
│   ├── public/
│   │   ├── _redirects
│   │   ├── browserconfig.xml
│   │   ├── demo-full.cast
│   │   ├── demo.cast
│   │   └── site.webmanifest
│   ├── shim.d.ts
│   ├── tsconfig.json
│   ├── uno.config.ts
│   └── vite.config.mts
├── go.mod
├── go.sum
├── hack/
│   ├── boilerplate.go.txt
│   ├── kind-config.yaml
│   ├── ollama-model-llama2-kind-cluster.yaml
│   ├── ollama-model-llama2-nfs.yaml
│   ├── ollama-model-phi-kind-cluster.yaml
│   └── ollama-model-phi-nfs.yaml
├── internal/
│   ├── cli/
│   │   └── kollama/
│   │       ├── cmd.go
│   │       ├── cmd_deploy.go
│   │       ├── cmd_expose.go
│   │       ├── cmd_undeploy.go
│   │       ├── common.go
│   │       └── wait_until.go
│   └── controller/
│       └── model_controller.go
└── pkg/
    ├── model/
    │   ├── image_store.go
    │   ├── model.go
    │   ├── model_test.go
    │   ├── pod.go
    │   ├── pod_test.go
    │   └── recorder.go
    └── operator/
        └── reconcile.go
Download .txt
SYMBOL INDEX (156 symbols across 19 files)

FILE: api/ollama/v1/model_types.go
  type ModelPersistentVolumeSpec (line 24) | type ModelPersistentVolumeSpec struct
  type ModelSpec (line 35) | type ModelSpec struct
  type ConditionType (line 107) | type ConditionType
  constant ModelUnknown (line 114) | ModelUnknown ConditionType = "Unknown"
  constant ModelAvailable (line 117) | ModelAvailable ConditionType = "Available"
  constant ModelProgressing (line 122) | ModelProgressing ConditionType = "Progressing"
  constant ModelReplicaFailure (line 125) | ModelReplicaFailure ConditionType = "ReplicaFailure"
  type ModelStatusCondition (line 128) | type ModelStatusCondition struct
  type ModelStatus (line 144) | type ModelStatus struct
  type Model (line 176) | type Model struct
  type ModelList (line 187) | type ModelList struct
  function init (line 193) | func init() {

FILE: api/ollama/v1/zz_generated.deepcopy.go
  method DeepCopyInto (line 29) | func (in *Model) DeepCopyInto(out *Model) {
  method DeepCopy (line 38) | func (in *Model) DeepCopy() *Model {
  method DeepCopyObject (line 48) | func (in *Model) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 56) | func (in *ModelList) DeepCopyInto(out *ModelList) {
  method DeepCopy (line 70) | func (in *ModelList) DeepCopy() *ModelList {
  method DeepCopyObject (line 80) | func (in *ModelList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 88) | func (in *ModelPersistentVolumeSpec) DeepCopyInto(out *ModelPersistentVo...
  method DeepCopy (line 98) | func (in *ModelPersistentVolumeSpec) DeepCopy() *ModelPersistentVolumeSp...
  method DeepCopyInto (line 108) | func (in *ModelSpec) DeepCopyInto(out *ModelSpec) {
  method DeepCopy (line 163) | func (in *ModelSpec) DeepCopy() *ModelSpec {
  method DeepCopyInto (line 173) | func (in *ModelStatus) DeepCopyInto(out *ModelStatus) {
  method DeepCopy (line 185) | func (in *ModelStatus) DeepCopy() *ModelStatus {
  method DeepCopyInto (line 195) | func (in *ModelStatusCondition) DeepCopyInto(out *ModelStatusCondition) {
  method DeepCopy (line 202) | func (in *ModelStatusCondition) DeepCopy() *ModelStatusCondition {

FILE: cmd/kollama/main.go
  function main (line 34) | func main() {

FILE: cmd/ollama-operator/main.go
  function init (line 47) | func init() {
  function main (line 54) | func main() {

FILE: docs/shim.d.ts
  type PlayerCreateOptions (line 2) | interface PlayerCreateOptions {
  type Player (line 24) | interface Player {

FILE: internal/cli/kollama/cmd.go
  function NewCmd (line 35) | func NewCmd(streams genericiooptions.IOStreams) *cobra.Command {

FILE: internal/cli/kollama/cmd_deploy.go
  constant deployExample (line 31) | deployExample = `
  constant deployedNonExposedMessage (line 45) | deployedNonExposedMessage = `🎉 Successfully deployed %s.
  constant deployedExposedMessage (line 61) | deployedExposedMessage = `🎉 Successfully deployed %s.
  type CmdDeployOptions (line 83) | type CmdDeployOptions struct
    method AddFlags (line 112) | func (o *CmdDeployOptions) AddFlags(flags *pflag.FlagSet) {
    method runE (line 195) | func (o *CmdDeployOptions) runE(cmd *cobra.Command, args []string) err...
  function NewCmdDeployOptions (line 105) | func NewCmdDeployOptions(streams genericiooptions.IOStreams) *CmdDeployO...
  function NewCmdDeploy (line 161) | func NewCmdDeploy(streams genericiooptions.IOStreams) *cobra.Command {

FILE: internal/cli/kollama/cmd_expose.go
  constant exposedMessage (line 27) | exposedMessage = `🎉 The model has been exposed through a service over %s.
  type CmdExposeOptions (line 48) | type CmdExposeOptions struct
    method AddFlags (line 71) | func (o *CmdExposeOptions) AddFlags(flags *pflag.FlagSet) {
    method runE (line 121) | func (o *CmdExposeOptions) runE(cmd *cobra.Command, args []string) err...
  function NewCmdExposeOptions (line 64) | func NewCmdExposeOptions(streams genericiooptions.IOStreams) *CmdExposeO...
  function NewCmdExpose (line 87) | func NewCmdExpose(streams genericiooptions.IOStreams) *cobra.Command {

FILE: internal/cli/kollama/cmd_undeploy.go
  constant unDeployExample (line 23) | unDeployExample = `
  type CmdUndeployOptions (line 37) | type CmdUndeployOptions struct
    method runE (line 87) | func (o *CmdUndeployOptions) runE(cmd *cobra.Command, args []string) e...
  function NewCmdUndeployOptions (line 47) | func NewCmdUndeployOptions(streams genericiooptions.IOStreams) *CmdUndep...
  function NewCmdUndeploy (line 54) | func NewCmdUndeploy(streams genericiooptions.IOStreams) *cobra.Command {

FILE: internal/cli/kollama/common.go
  function isKubectlPlugin (line 34) | func isKubectlPlugin() (bool, error) {
  function command (line 48) | func command() string {
  function IsOllamaOperatorCRDSupported (line 57) | func IsOllamaOperatorCRDSupported(discoveryClient discovery.DiscoveryInt...
  function FromUnstructured (line 79) | func FromUnstructured[T any](obj *unstructured.Unstructured) (*T, error) {
  function Unstructured (line 90) | func Unstructured[T runtime.Object](obj T) (*unstructured.Unstructured, ...
  function getOllama (line 105) | func getOllama(ctx context.Context, dynamicClient dynamic.Interface, nam...
  function getNamespace (line 126) | func getNamespace(clientConfig clientcmd.ClientConfig, cmd *cobra.Comman...
  function getImage (line 148) | func getImage(cmd *cobra.Command, args []string) (string, error) {
  function createOllamaModel (line 163) | func createOllamaModel(
  function exposeOllamaModel (line 215) | func exposeOllamaModel(

FILE: internal/cli/kollama/wait_until.go
  constant isReadyString (line 20) | isReadyString = " is ready"
  function waitUntilImageStoreReady (line 23) | func waitUntilImageStoreReady(ctx context.Context, kubeClient client.Cli...
  function waitUntilImageStoreServiceReady (line 39) | func waitUntilImageStoreServiceReady(ctx context.Context, kubeClient cli...
  function waitUntilOllamaModelDeploymentPullImageDone (line 55) | func waitUntilOllamaModelDeploymentPullImageDone(ctx context.Context, ku...
  function waitUntilOllamaModelDeploymentReady (line 78) | func waitUntilOllamaModelDeploymentReady(ctx context.Context, kubeClient...
  function waitUntilOllamaModelServiceReady (line 99) | func waitUntilOllamaModelServiceReady(ctx context.Context, kubeClient cl...
  function waitUntilModelAvailable (line 115) | func waitUntilModelAvailable(kubeClient client.Client, namespace string,...

FILE: internal/controller/model_controller.go
  type ModelReconciler (line 35) | type ModelReconciler struct
    method Reconcile (line 60) | func (r *ModelReconciler) Reconcile(ctx context.Context, req ctrl.Requ...
    method SetupWithManager (line 77) | func (r *ModelReconciler) SetupWithManager(mgr ctrl.Manager) error {
    method reconcile (line 83) | func (r *ModelReconciler) reconcile(ctx context.Context, req ctrl.Requ...
    method reconcilePVC (line 108) | func (r *ModelReconciler) reconcilePVC(ctx context.Context, ns string,...
    method reconcileStatefulSet (line 121) | func (r *ModelReconciler) reconcileStatefulSet(ctx context.Context, ns...
    method reconcileService (line 139) | func (r *ModelReconciler) reconcileService(ctx context.Context, ns str...
    method reconcileDeployment (line 162) | func (r *ModelReconciler) reconcileDeployment(ctx context.Context, ns ...
    method reconcileModelService (line 189) | func (r *ModelReconciler) reconcileModelService(ctx context.Context, n...

FILE: pkg/model/image_store.go
  constant ImageStorePVCName (line 21) | ImageStorePVCName         = "ollama-models-store-pvc"
  constant ImageStoreStatefulSetName (line 22) | ImageStoreStatefulSetName = "ollama-models-store"
  function getImageStorePVC (line 25) | func getImageStorePVC(ctx context.Context, client client.Client, namespa...
  function EnsureImageStorePVCCreated (line 40) | func EnsureImageStorePVCCreated(
  function GetImageStorePVByPVC (line 96) | func GetImageStorePVByPVC(ctx context.Context, c client.Client, pvc *cor...
  function getImageStoreStatefulSet (line 111) | func getImageStoreStatefulSet(ctx context.Context, client client.Client,...
  function EnsureImageStoreStatefulSetCreated (line 126) | func EnsureImageStoreStatefulSetCreated(
  function IsImageStoreStatefulSetReady (line 195) | func IsImageStoreStatefulSetReady(
  function getImageStoreService (line 222) | func getImageStoreService(ctx context.Context, client client.Client, nam...
  function EnsureImageStoreServiceCreated (line 237) | func EnsureImageStoreServiceCreated(
  function IsImageStoreServiceReady (line 296) | func IsImageStoreServiceReady(

FILE: pkg/model/model.go
  function getServiceByLabels (line 22) | func getServiceByLabels(ctx context.Context, c client.Client, namespace ...
  function ModelServiceName (line 40) | func ModelServiceName(name string) string {
  function ModelAppName (line 44) | func ModelAppName(name string) string {
  function ModelLabels (line 48) | func ModelLabels(name string) map[string]string {
  function OllamaModelNameFromNameReference (line 57) | func OllamaModelNameFromNameReference(ref namepkg.Reference) string {
  function ImageStoreLabels (line 66) | func ImageStoreLabels() map[string]string {
  function ModelAnnotations (line 73) | func ModelAnnotations(name string, imageStore bool) map[string]string {
  function getDeployment (line 77) | func getDeployment(ctx context.Context, c client.Client, namespace strin...
  function EnsureDeploymentCreated (line 92) | func EnsureDeploymentCreated(
  function MergePodTemplate (line 155) | func MergePodTemplate(
  function AssignOrAppend (line 211) | func AssignOrAppend[T any](source []T, predicate func(item T) bool, modi...
  function AppendIfNotFound (line 224) | func AppendIfNotFound[T any](source []T, predicate func(item T) bool, ne...
  function IsDeploymentReady (line 233) | func IsDeploymentReady(
  function UpdateDeployment (line 267) | func UpdateDeployment(
  function NewServiceForModel (line 309) | func NewServiceForModel(namespace, name string, deployment *appsv1.Deplo...
  function EnsureServiceCreated (line 338) | func EnsureServiceCreated(
  function IsServiceReady (line 368) | func IsServiceReady(
  function IsProgressing (line 398) | func IsProgressing(ctx context.Context, ollamaModelResource ollamav1.Mod...
  function SetProgressing (line 404) | func SetProgressing(
  function IsAvailable (line 433) | func IsAvailable(ctx context.Context, ollamaModelResource ollamav1.Model...
  function SetAvailable (line 439) | func SetAvailable(
  function ShouldSetReplicas (line 469) | func ShouldSetReplicas(
  function SetReplicas (line 483) | func SetReplicas(

FILE: pkg/model/model_test.go
  function TestModelNameFromImage (line 12) | func TestModelNameFromImage(t *testing.T) {

FILE: pkg/model/pod.go
  constant OllamaBaseImage (line 17) | OllamaBaseImage = "ollama/ollama"
  function FindOllamaServerContainer (line 20) | func FindOllamaServerContainer(container corev1.Container) bool {
  function UniqEnvVar (line 24) | func UniqEnvVar(env []corev1.EnvVar) []corev1.EnvVar {
  function AssignOllamaServerContainer (line 30) | func AssignOllamaServerContainer(readOnly bool, resources corev1.Resourc...
  function NewOllamaServerContainer (line 111) | func NewOllamaServerContainer(readOnly bool, resources corev1.ResourceRe...
  function FindOllamaPullerContainer (line 173) | func FindOllamaPullerContainer(container corev1.Container) bool {
  function ioReaderOfJsonBody (line 177) | func ioReaderOfJsonBody(body map[string]any) (io.Reader, error) {
  function ollamaPull (line 188) | func ollamaPull(image string) string {
  function ollamaGenerate (line 197) | func ollamaGenerate(image string) string {
  function AssignOllamaPullerContainer (line 206) | func AssignOllamaPullerContainer(name string, image string, parsedModelN...
  function NewOllamaPullerContainer (line 231) | func NewOllamaPullerContainer(name string, image string, parsedModelName...

FILE: pkg/model/pod_test.go
  function TestOllamaPull (line 9) | func TestOllamaPull(t *testing.T) {
  function TestOllamaGenerate (line 14) | func TestOllamaGenerate(t *testing.T) {

FILE: pkg/model/recorder.go
  type WrappedRecorder (line 11) | type WrappedRecorder struct
  function NewWrappedRecorder (line 16) | func NewWrappedRecorder[T runtime.Object](recorder record.EventRecorder,...
  method Event (line 23) | func (r *WrappedRecorder[T]) Event(eventType, reason, message string) {
  method Eventf (line 28) | func (r *WrappedRecorder[T]) Eventf(eventType, reason, messageFmt string...
  method AnnotatedEventf (line 33) | func (r *WrappedRecorder[T]) AnnotatedEventf(annotations map[string]stri...
  type baseWrapperRecorderContextKey (line 37) | type baseWrapperRecorderContextKey
  function NewWrappedRecorderContextKey (line 39) | func NewWrappedRecorderContextKey(key string) baseWrapperRecorderContext...
  constant defaultBaseWrapperRecorderContextKey (line 44) | defaultBaseWrapperRecorderContextKey baseWrapperRecorderContextKey = "de...
  function WithWrappedRecorder (line 47) | func WithWrappedRecorder[T runtime.Object](ctx context.Context, recorder...
  function WrappedRecorderFromContext (line 55) | func WrappedRecorderFromContext[T runtime.Object](ctx context.Context, k...
  type baseClientContextKey (line 66) | type baseClientContextKey
  constant defaultBaseClientContextKey (line 69) | defaultBaseClientContextKey baseClientContextKey = "default"
  function NewClientContextKey (line 72) | func NewClientContextKey(key string) baseClientContextKey {
  function WithClient (line 76) | func WithClient(ctx context.Context, client client.Client, key ...baseCl...
  function ClientFromContext (line 84) | func ClientFromContext(ctx context.Context, key ...baseClientContextKey)...

FILE: pkg/operator/reconcile.go
  function ResultFromError (line 17) | func ResultFromError(err error) (*ctrl.Result, error) {
  function HandleError (line 30) | func HandleError(ctx context.Context, result *ctrl.Result, err error) (c...
  type SubReconciler (line 45) | type SubReconciler struct
  type SubReconcilers (line 52) | type SubReconcilers
  method Reconcile (line 54) | func (s SubReconcilers[T]) Reconcile(ctx context.Context, req ctrl.Reque...
  function NewSubReconcilers (line 69) | func NewSubReconcilers[T runtime.Object](reconcilers ...SubReconciler[T]...
  type ReconcileHandler (line 73) | type ReconcileHandler
  function NewPVCReconciler (line 75) | func NewPVCReconciler[T runtime.Object](fn ReconcileHandler[T]) SubRecon...
  function NewStatefulSetReconciler (line 84) | func NewStatefulSetReconciler[T runtime.Object](fn ReconcileHandler[T]) ...
  function NewServiceReconciler (line 93) | func NewServiceReconciler[T runtime.Object](fn ReconcileHandler[T]) SubR...
  function NewDeploymentReconciler (line 102) | func NewDeploymentReconciler[T runtime.Object](fn ReconcileHandler[T]) S...
  function RequeueAfter (line 111) | func RequeueAfter(d time.Duration) error {
  function RequeueAfterWithError (line 115) | func RequeueAfterWithError(d time.Duration, err error) error {
  type RequeueError (line 119) | type RequeueError struct
    method Error (line 124) | func (r *RequeueError) Error() string {
    method Result (line 132) | func (r *RequeueError) Result() reconcile.Result {
Condensed preview — 124 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,076K chars).
[
  {
    "path": ".dockerignore",
    "chars": 120,
    "preview": "# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file\n# Ignore build and test binaries.\nbin/\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 758,
    "preview": "# These are supported funding model platforms\n\ngithub: [nekomeowww]\n# patreon: # Replace with a single Patreon username\n"
  },
  {
    "path": ".github/renovate.json",
    "chars": 415,
    "preview": "{\n    \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n    \"automerge\": true,\n    \"extends\": [\n      \"con"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "chars": 1175,
    "preview": "name: CI\n\non:\n  push:\n    paths-ignore:\n      - 'docs/pages/**'\n    branches:\n      - main\n  pull_request:\n    paths-ign"
  },
  {
    "path": ".github/workflows/pr-docs-build.yaml",
    "chars": 2313,
    "preview": "name: Build PR Previewing Docs\n\non:\n  pull_request:\n    branches:\n      - main\n    paths:\n      - 'docs/**'\n\njobs:\n  bui"
  },
  {
    "path": ".github/workflows/pr-docs-deployment.yaml",
    "chars": 4459,
    "preview": "name: Push PR Previewing Docs to Cloudflare Pages\n\non:\n  workflow_run:\n    workflows:\n      - Build PR Previewing Docs\n "
  },
  {
    "path": ".github/workflows/production-docs-deployment.yaml",
    "chars": 1788,
    "preview": "name: Build Docs to Cloudflare Pages\n\non:\n  push:\n    branches:\n      - 'main'\n\njobs:\n  build:\n    name: Build\n    runs-"
  },
  {
    "path": ".github/workflows/release-build.yml",
    "chars": 2700,
    "preview": "name: Release Build\n\non:\n  push:\n    tags:\n      - '**'\n  workflow_dispatch:\n\njobs:\n  goreleaser:\n    name: kollama - Bu"
  },
  {
    "path": ".github/workflows/unstable-build.yml",
    "chars": 1538,
    "preview": "name: Unstable Build\n\non:\n  workflow_dispatch:\n\njobs:\n  ghcr_build:\n    name: Build for GitHub Container Registry\n    pe"
  },
  {
    "path": ".gitignore",
    "chars": 706,
    "preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\nbin/*\nDockerfile.cross\n\n# Built application files\n!d"
  },
  {
    "path": ".golangci.yml",
    "chars": 2090,
    "preview": "version: \"2\"\nrun:\n  allow-parallel-runners: true\nlinters:\n  default: all\n  disable:\n    - containedctx\n    - contextchec"
  },
  {
    "path": ".goreleaser.yml",
    "chars": 479,
    "preview": "project_name: kollama\nrelease:\n  github:\n    owner: nekomeowww\n    name: ollama-operator\nbuilds:\n  - id: kollama\n    goo"
  },
  {
    "path": ".krew.yaml",
    "chars": 1755,
    "preview": "apiVersion: krew.googlecontainertools.github.com/v1alpha2\nkind: Plugin\nmetadata:\n  name: kollama\nspec:\n  version: {{ .Ta"
  },
  {
    "path": ".tool-versions",
    "chars": 35,
    "preview": "golang 1.26.1\ngolangci-lint 2.11.3\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 560,
    "preview": "{\n    \"editor.formatOnSave\": false,\n    \"editor.codeActionsOnSave\": {\n        \"source.fixAll.eslint\": \"explicit\",\n      "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4178,
    "preview": "# Contributing to Ollama Operator\n\n### Prerequisites\n\n- `go` version `v1.24.0+`\n- `docker` version `17.03+`.\n- `kubectl`"
  },
  {
    "path": "Dockerfile",
    "chars": 1410,
    "preview": "# Build the manager binary\nFROM golang:1.26 AS builder\n\nARG TARGETOS\nARG TARGETARCH\n\nWORKDIR /workspace\n\n# Copy the Go M"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "Makefile",
    "chars": 8693,
    "preview": "# Image URL to use all building/pushing image targets\nIMG ?= ghcr.io/nekomeowww/ollama-operator:0.10.7\n# ENVTEST_K8S_VER"
  },
  {
    "path": "PROJECT",
    "chars": 544,
    "preview": "# Code generated by tool. DO NOT EDIT.\n# This file is used to track the info used to scaffold your project\n# and allow t"
  },
  {
    "path": "README.md",
    "chars": 7206,
    "preview": "<div align=\"center\">\n  <img alt=\"ollama\" height=\"200px\" src=\"./docs/public/logo.png\">\n</div>\n\n# Ollama Operator\n\n[![Disc"
  },
  {
    "path": "api/ollama/v1/groupversion_info.go",
    "chars": 1201,
    "preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "api/ollama/v1/model_types.go",
    "chars": 10016,
    "preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "api/ollama/v1/zz_generated.deepcopy.go",
    "chars": 6051,
    "preview": "//go:build !ignore_autogenerated\n\n/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyo"
  },
  {
    "path": "cmd/kollama/main.go",
    "chars": 1360,
    "preview": "/*\nCopyright 2018 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "cmd/ollama-operator/main.go",
    "chars": 5151,
    "preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "config/crd/bases/ollama.ayaka.io_models.yaml",
    "chars": 616651,
    "preview": "---\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubeb"
  },
  {
    "path": "config/crd/kustomization.yaml",
    "chars": 969,
    "preview": "# This kustomization.yaml is not intended to be run by itself,\n# since it depends on service name and namespace that are"
  },
  {
    "path": "config/crd/kustomizeconfig.yaml",
    "chars": 506,
    "preview": "# This file is for teaching kustomize how to substitute name and namespace reference in CRD\nnameReference:\n- kind: Servi"
  },
  {
    "path": "config/default/kustomization.yaml",
    "chars": 4675,
    "preview": "# Adds namespace to all resources.\nnamespace: ollama-operator-system\n\n# Value of this field is prepended to the\n# names "
  },
  {
    "path": "config/default/manager_auth_proxy_patch.yaml",
    "chars": 1093,
    "preview": "# This patch inject a sidecar container which is a HTTP proxy for the\n# controller manager, it performs RBAC authorizati"
  },
  {
    "path": "config/default/manager_config_patch.yaml",
    "chars": 162,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: controller-manager\n  namespace: system\nspec:\n  template:\n    spec"
  },
  {
    "path": "config/manager/kustomization.yaml",
    "chars": 181,
    "preview": "resources:\n- manager.yaml\napiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nimages:\n- name: controller\n  n"
  },
  {
    "path": "config/manager/manager.yaml",
    "chars": 3497,
    "preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n  labels:\n    control-plane: controller-manager\n    app.kubernetes.io/name: nam"
  },
  {
    "path": "config/prometheus/kustomization.yaml",
    "chars": 26,
    "preview": "resources:\n- monitor.yaml\n"
  },
  {
    "path": "config/prometheus/monitor.yaml",
    "chars": 782,
    "preview": "# Prometheus Monitor Service (Metrics)\napiVersion: monitoring.coreos.com/v1\nkind: ServiceMonitor\nmetadata:\n  labels:\n   "
  },
  {
    "path": "config/rbac/auth_proxy_client_clusterrole.yaml",
    "chars": 437,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    app.kubernetes.io/name: clusterrole\n "
  },
  {
    "path": "config/rbac/auth_proxy_role.yaml",
    "chars": 563,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    app.kubernetes.io/name: clusterrole\n "
  },
  {
    "path": "config/rbac/auth_proxy_role_binding.yaml",
    "chars": 565,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io/name: cluste"
  },
  {
    "path": "config/rbac/auth_proxy_service.yaml",
    "chars": 579,
    "preview": "apiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    control-plane: controller-manager\n    app.kubernetes.io/name: servi"
  },
  {
    "path": "config/rbac/kustomization.yaml",
    "chars": 693,
    "preview": "resources:\n# All RBAC will be applied under this service account in\n# the deployment namespace. You may comment out this"
  },
  {
    "path": "config/rbac/leader_election_role.yaml",
    "chars": 751,
    "preview": "# permissions to do leader election.\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  labels:\n    app.kub"
  },
  {
    "path": "config/rbac/leader_election_role_binding.yaml",
    "chars": 563,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io/name: rolebinding\n "
  },
  {
    "path": "config/rbac/model_editor_role.yaml",
    "chars": 642,
    "preview": "# permissions for end users to edit models.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  label"
  },
  {
    "path": "config/rbac/model_viewer_role.yaml",
    "chars": 599,
    "preview": "# permissions for end users to view models.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  label"
  },
  {
    "path": "config/rbac/role.yaml",
    "chars": 1065,
    "preview": "---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: manager-role\nrules:\n- apiGroups:\n  - \"\""
  },
  {
    "path": "config/rbac/role_binding.yaml",
    "chars": 560,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io/name: cluste"
  },
  {
    "path": "config/rbac/service_account.yaml",
    "chars": 191,
    "preview": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    app.kubernetes.io/name: ollama-operator\n    app.kubernetes.i"
  },
  {
    "path": "config/samples/kustomization.yaml",
    "chars": 120,
    "preview": "## Append samples of your project ##\nresources:\n- ollama_v1_model.yaml\n#+kubebuilder:scaffold:manifestskustomizesamples\n"
  },
  {
    "path": "config/samples/ollama_v1_model.yaml",
    "chars": 191,
    "preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n  labels:\n    app.kubernetes.io/name: ollama-operator\n    app.kuber"
  },
  {
    "path": "cspell.config.yaml",
    "chars": 1721,
    "preview": "version: \"0.2\"\nignorePaths: []\ndictionaryDefinitions: []\ndictionaries: []\nwords:\n  - alices\n  - AnnotatedEventf\n  - antf"
  },
  {
    "path": "docs/.editorconfig",
    "chars": 147,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
  },
  {
    "path": "docs/.vitepress/config.mts",
    "chars": 8359,
    "preview": "import { defineConfig } from 'vitepress'\nimport { tabsMarkdownPlugin } from 'vitepress-plugin-tabs'\n\n// https://vitepres"
  },
  {
    "path": "docs/.vitepress/theme/components/GettingStartedBlocksEn.vue",
    "chars": 3854,
    "preview": "<template>\n  <TitleBlockContainerGroup>\n    <TitleBlockContainer\n      href=\"/pages/en/guide/getting-started/cli\"\n      "
  },
  {
    "path": "docs/.vitepress/theme/components/GettingStartedBlocksZhCn.vue",
    "chars": 3733,
    "preview": "<template>\n  <TitleBlockContainerGroup>\n    <TitleBlockContainer\n      href=\"/pages/zh-CN/guide/getting-started/cli\"\n   "
  },
  {
    "path": "docs/.vitepress/theme/components/TitleBlockContainer.vue",
    "chars": 690,
    "preview": "<script setup lang=\"ts\">\nconst props = defineProps<{\n  title?: string\n  href?: string\n}>()\n</script>\n\n<template>\n  <a\n  "
  },
  {
    "path": "docs/.vitepress/theme/components/TitleBlockContainerGroup.vue",
    "chars": 92,
    "preview": "<template>\n  <div flex=\"~ row <md:col\" w-full my-4 gap-4>\n    <slot />\n  </div>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/index.mts",
    "chars": 2630,
    "preview": "// https://vitepress.dev/guide/custom-theme\nimport { h } from 'vue'\nimport type { Theme } from 'vitepress'\nimport Defaul"
  },
  {
    "path": "docs/.vitepress/theme/style.css",
    "chars": 4277,
    "preview": "/**\n * Customize default theme styling by overriding CSS variables:\n * https://github.com/vuejs/vitepress/blob/main/src/"
  },
  {
    "path": "docs/eslint.config.js",
    "chars": 134,
    "preview": "import antfu from '@antfu/eslint-config'\n\nexport default antfu({\n  ignores: [\n    '**/*.md',\n    '**/*.yaml',\n    '**/*."
  },
  {
    "path": "docs/package.json",
    "chars": 1206,
    "preview": "{\n  \"name\": \"docs\",\n  \"type\": \"module\",\n  \"packageManager\": \"pnpm@10.32.1\",\n  \"scripts\": {\n    \"docs:dev\": \"vitepress de"
  },
  {
    "path": "docs/pages/en/acknowledgements.md",
    "chars": 338,
    "preview": "# Acknowledgements\n\nGratefully thanks to the following projects and their authors, contributors:\n\n- [Ollama](https://git"
  },
  {
    "path": "docs/pages/en/guide/getting-started/cli.md",
    "chars": 965,
    "preview": "# Deploy through `kollama` CLI\n\nWe have a CLI called `kollama` here to simplify the deployment process. It is a simple w"
  },
  {
    "path": "docs/pages/en/guide/getting-started/crd.md",
    "chars": 2489,
    "preview": "# Deploy models through CRD\n\n## Deploy the model\n\n1. Create one [`Model` CRD](/pages/en/references/crd/model) to rule th"
  },
  {
    "path": "docs/pages/en/guide/getting-started/index.md",
    "chars": 620,
    "preview": "# Getting Started\n\n## Install operator\n\n<!--@include: @/pages/en/snippets/deploy-kubernetes-cluster-with-kind.md-->\n\n<!-"
  },
  {
    "path": "docs/pages/en/guide/overview.md",
    "chars": 3512,
    "preview": "# Overview\n\nWhile [Ollama](https://github.com/ollama/ollama) is a powerful tool for running large language models locall"
  },
  {
    "path": "docs/pages/en/guide/supported-models.md",
    "chars": 5220,
    "preview": "# Supported models\n\nThe out of box supported models are listed below.\nYou can use them directly by specifying the model "
  },
  {
    "path": "docs/pages/en/index.md",
    "chars": 1754,
    "preview": "---\nlayout: home\nsidebar: false\n\ntitle: Ollama Operator\n\nhero:\n  name: Ollama Operator\n  text: Large language models, sc"
  },
  {
    "path": "docs/pages/en/references/architectural-design.md",
    "chars": 1915,
    "preview": "# Architectural Design\n\nThere are two major components that the Ollama Operator will create for:\n\n1. **Model Inferencing"
  },
  {
    "path": "docs/pages/en/references/cli/commands/deploy.md",
    "chars": 9779,
    "preview": "# `kollama deploy`\n\n`kollama deploy` command is used to deploy a [`Model`](/pages/en/references/crd/model) to the Kubern"
  },
  {
    "path": "docs/pages/en/references/cli/commands/expose.md",
    "chars": 4090,
    "preview": "# `kollama expose`\n\n`kolamma expose` is a command to expose a [`Model`](/pages/en/references/crd/model) as a service.\n\n["
  },
  {
    "path": "docs/pages/en/references/cli/commands/undeploy.md",
    "chars": 1443,
    "preview": "# `kollama undeploy`\n\n::: info No need to worry about deleting past [`Model`](/pages/en/references/crd/model) deployment"
  },
  {
    "path": "docs/pages/en/references/cli/index.md",
    "chars": 220,
    "preview": "# `kollama` CLI Reference\n\n- [`kollama deploy`](/pages/en/references/cli/commands/deploy)\n- [`kollama undeploy`](/pages/"
  },
  {
    "path": "docs/pages/en/references/crd/index.md",
    "chars": 61,
    "preview": "# CRD Reference\n\n- [`Model`](/pages/en/references/crd/model)\n"
  },
  {
    "path": "docs/pages/en/references/crd/model.md",
    "chars": 1155,
    "preview": "# `Model`\n\n`Model` is a custom resource definition (CRD) that represents a Ollama server instance in the cluster.\n\nWhen "
  },
  {
    "path": "docs/pages/en/snippets/deploy-kubernetes-cluster-with-kind.md",
    "chars": 1166,
    "preview": "::: tip Don't have an existing Kubernetes cluster?\n\nRun the following commands to create a new Kubernetes cluster with `"
  },
  {
    "path": "docs/pages/en/snippets/install-ollama-operator.md",
    "chars": 356,
    "preview": "1. Install operator.\n\n```shell\nkubectl apply \\\n  --server-side=true \\\n  -f https://raw.githubusercontent.com/nekomeowww/"
  },
  {
    "path": "docs/pages/zh-CN/acknowledgements.md",
    "chars": 213,
    "preview": "# 致谢\n\n非常感谢以下项目的作者和贡献者:\n\n- [Ollama](https://github.com/ollama/ollama)\n- [llama.cpp](https://github.com/ggerganov/llama.cp"
  },
  {
    "path": "docs/pages/zh-CN/guide/getting-started/cli.md",
    "chars": 812,
    "preview": "# 通过 `kollama` CLI 进行部署\n\n我们有一个名为 `kollama` 的 CLI 来简化部署过程。这是一种将 Ollama 模型部署到 Kubernetes 集群的简单方法。\n\n## 开始操作\n\n1. 通过 `go inst"
  },
  {
    "path": "docs/pages/zh-CN/guide/getting-started/crd.md",
    "chars": 2031,
    "preview": "# 通过 CRD 部署\n\n## 部署模型\n\n1. 创建一个 [`Model`](/pages/zh-CN/references/crd/model) 类型的 CRD 资源\n\n::: tip 什么是 CRD?\n\nCRD 是 Kubernete"
  },
  {
    "path": "docs/pages/zh-CN/guide/getting-started/index.md",
    "chars": 395,
    "preview": "# 快速上手\n\n## 安装 Ollama Operator\n\n<!--@include: @/pages/zh-CN/snippets/deploy-kubernetes-cluster-with-kind.md-->\n\n<!--@incl"
  },
  {
    "path": "docs/pages/zh-CN/guide/overview.md",
    "chars": 2265,
    "preview": "# 概览\n\n即便 [Ollama](https://github.com/ollama/ollama) 已经是一个强大的用于在本地运行大型语言模型的工具,并且 CLI 的用户体验与使用 Docker CLI 相同,但可惜的是,目前还无法在 "
  },
  {
    "path": "docs/pages/zh-CN/guide/supported-models.md",
    "chars": 4545,
    "preview": "# 支持的模型\n\n支持的开箱即用的模型列表如下。\n您可以通过在 `Model` CRD 中指定模型镜像字段 `image` 来直接使用它们。\n\n> [!TIP] 不止这些\n> 借助由 Ollama 支持的 [`Modelfile`](htt"
  },
  {
    "path": "docs/pages/zh-CN/index.md",
    "chars": 1325,
    "preview": "---\nlayout: home\nsidebar: false\n\ntitle: Ollama Operator\n\nhero:\n  name: Ollama Operator\n  text: 大语言模型,伸缩自如,轻松部署\n  tagline"
  },
  {
    "path": "docs/pages/zh-CN/references/architectural-design.md",
    "chars": 1086,
    "preview": "# 架构设计\n\nOllama Operator 会根据 CRD 的定义,创建两个主要组件:\n\n1. **模型推理服务**:模型推断服务器是一个简单的 API 服务器,用于运行模型并为模型的 API 提供服务。它在 Kubernetes 集群"
  },
  {
    "path": "docs/pages/zh-CN/references/cli/commands/deploy.md",
    "chars": 8694,
    "preview": "# `kollama deploy`\n\n`kollama deploy` 命令用于将 [`Model`](/pages/zh-CN/references/crd/model) 部署到 Kubernetes 集群。它是通过操作 CRD 资源与"
  },
  {
    "path": "docs/pages/zh-CN/references/cli/commands/expose.md",
    "chars": 2904,
    "preview": "# `kollama expose`\n\n`kollama expose` 用于暴露 [`Model`](/pages/zh-CN/references/crd/model) 服务。\n\n[[toc]]\n\n## 用例\n\n### 暴露 [`Mod"
  },
  {
    "path": "docs/pages/zh-CN/references/cli/commands/undeploy.md",
    "chars": 949,
    "preview": "# `kollama undeploy`\n\n::: info 无需担心删除过去的 [`Model`](/pages/zh-CN/references/crd/model) 部署后会需要重新下载模型镜像哦!\n\nOllama Operator "
  },
  {
    "path": "docs/pages/zh-CN/references/cli/index.md",
    "chars": 222,
    "preview": "# `kollama` CLI 参考\n\n- [`kollama deploy`](/pages/zh-CN/references/cli/commands/deploy)\n- [`kollama undeploy`](/pages/zh-C"
  },
  {
    "path": "docs/pages/zh-CN/references/crd/index.md",
    "chars": 57,
    "preview": "# CRD 参考\n\n- [`Model`](/pages/zh-CN/references/crd/model)\n"
  },
  {
    "path": "docs/pages/zh-CN/references/crd/model.md",
    "chars": 987,
    "preview": "# `Model` 模型资源\n\n`Model` 是一个自定义资源定义(CRD),代表集群中的一个 Ollama 推理服务实例。\n\n创建时,`Model` 的创建会触发对 [`Deployment`](https://kubernetes.i"
  },
  {
    "path": "docs/pages/zh-CN/snippets/deploy-kubernetes-cluster-with-kind.md",
    "chars": 1128,
    "preview": "::: tip 没有现成的 Kubernetes 集群吗?\n\n运行以下命令以在您的本地机器上安装 Docker 和 kind 并创建一个 Kubernetes 集群:\n\n::: code-group\n\n```shell [macOS]\nbr"
  },
  {
    "path": "docs/pages/zh-CN/snippets/install-ollama-operator.md",
    "chars": 332,
    "preview": "1. 安装 Operator.\n\n```shell\nkubectl apply \\\n  --server-side=true \\\n  -f https://raw.githubusercontent.com/nekomeowww/ollam"
  },
  {
    "path": "docs/public/_redirects",
    "chars": 22,
    "preview": "/  /pages/en/     301\n"
  },
  {
    "path": "docs/public/browserconfig.xml",
    "chars": 246,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square150x150logo"
  },
  {
    "path": "docs/public/demo-full.cast",
    "chars": 65973,
    "preview": "{\"version\": 2, \"width\": 185, \"height\": 48, \"timestamp\": 1712909764, \"env\": {\"SHELL\": \"/bin/zsh\", \"TERM\": \"xterm-256color"
  },
  {
    "path": "docs/public/demo.cast",
    "chars": 37251,
    "preview": "{\"version\": 2, \"width\": 110, \"height\": 32, \"timestamp\": 1712912885, \"env\": {\"SHELL\": \"/bin/zsh\", \"TERM\": \"xterm-256color"
  },
  {
    "path": "docs/public/site.webmanifest",
    "chars": 426,
    "preview": "{\n    \"name\": \"\",\n    \"short_name\": \"\",\n    \"icons\": [\n        {\n            \"src\": \"/android-chrome-192x192.png\",\n     "
  },
  {
    "path": "docs/shim.d.ts",
    "chars": 892,
    "preview": "declare module 'asciinema-player' {\n  interface PlayerCreateOptions {\n    cols?: number;\n    rows?: number;\n    autoPlay"
  },
  {
    "path": "docs/tsconfig.json",
    "chars": 671,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"jsx\": \"preserve\",\n    \"lib\": [\n      \"DOM\",\n      \"ESNext\"\n    ],\n"
  },
  {
    "path": "docs/uno.config.ts",
    "chars": 455,
    "preview": "import { defineConfig, presetAttributify, presetIcons, presetUno } from 'unocss'\n\nexport default defineConfig({\n  shortc"
  },
  {
    "path": "docs/vite.config.mts",
    "chars": 977,
    "preview": "import { join } from 'node:path'\nimport { defineConfig } from 'vite'\nimport UnoCSS from 'unocss/vite'\nimport Inspect fro"
  },
  {
    "path": "go.mod",
    "chars": 5054,
    "preview": "module github.com/nekomeowww/ollama-operator\n\ngo 1.25.7\n\ntoolchain go1.26.1\n\nrequire (\n\tgithub.com/briandowns/spinner v1"
  },
  {
    "path": "go.sum",
    "chars": 29445,
    "preview": "entgo.io/ent v0.14.5 h1:Rj2WOYJtCkWyFo6a+5wB3EfBRP0rnx1fMk6gGA0UUe4=\nentgo.io/ent v0.14.5/go.mod h1:zTzLmWtPvGpmSwtkaayM"
  },
  {
    "path": "hack/boilerplate.go.txt",
    "chars": 546,
    "preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "hack/kind-config.yaml",
    "chars": 375,
    "preview": "kind: Cluster\napiVersion: kind.x-k8s.io/v1alpha4\nnodes:\n- role: control-plane\n- role: worker\n  extraPortMappings:\n  - co"
  },
  {
    "path": "hack/ollama-model-llama2-kind-cluster.yaml",
    "chars": 140,
    "preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n  name: llama2\nspec:\n  image: llama2\n  persistentVolume:\n    access"
  },
  {
    "path": "hack/ollama-model-llama2-nfs.yaml",
    "chars": 118,
    "preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n  name: llama2\nspec:\n  image: llama2\n  storageClassName: nfs-csi\n"
  },
  {
    "path": "hack/ollama-model-phi-kind-cluster.yaml",
    "chars": 134,
    "preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n  name: phi\nspec:\n  image: phi\n  persistentVolume:\n    accessMode: "
  },
  {
    "path": "hack/ollama-model-phi-nfs.yaml",
    "chars": 112,
    "preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n  name: phi\nspec:\n  image: phi\n  storageClassName: nfs-csi\n"
  },
  {
    "path": "internal/cli/kollama/cmd.go",
    "chars": 1336,
    "preview": "/*\nCopyright 2018 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
  },
  {
    "path": "internal/cli/kollama/cmd_deploy.go",
    "chars": 9111,
    "preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/briandowns/spinner\"\n\t\""
  },
  {
    "path": "internal/cli/kollama/cmd_expose.go",
    "chars": 4670,
    "preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/samber/lo\"\n\t\"github.com/spf"
  },
  {
    "path": "internal/cli/kollama/cmd_undeploy.go",
    "chars": 2961,
    "preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/samber/lo\"\n\t\"github.com/spf13/cobra\"\n\n\tmetav"
  },
  {
    "path": "internal/cli/kollama/common.go",
    "chars": 6386,
    "preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcor"
  },
  {
    "path": "internal/cli/kollama/wait_until.go",
    "chars": 4886,
    "preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gookit/color\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8"
  },
  {
    "path": "internal/controller/model_controller.go",
    "chars": 7156,
    "preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "pkg/model/image_store.go",
    "chars": 8471,
    "preview": "package model\n\nimport (\n\t\"context\"\n\n\t\"github.com/samber/lo\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\""
  },
  {
    "path": "pkg/model/model.go",
    "chars": 13006,
    "preview": "package model\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\n\tnamepkg \"github.com/google/go-containerregistry/pkg/name\"\n\t\"github"
  },
  {
    "path": "pkg/model/model_test.go",
    "chars": 1397,
    "preview": "package model\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\t\"github.com/str"
  },
  {
    "path": "pkg/model/pod.go",
    "chars": 7480,
    "preview": "package model\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/samber/lo\"\n\tcorev1 \"k8s.io/"
  },
  {
    "path": "pkg/model/pod_test.go",
    "chars": 556,
    "preview": "package model\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestOllamaPull(t *testing.T) {\n\tcomman"
  },
  {
    "path": "pkg/model/recorder.go",
    "chars": 2639,
    "preview": "package model\n\nimport (\n\t\"context\"\n\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/client-go/tools/record\"\n\t\"sigs.k8s.io/co"
  },
  {
    "path": "pkg/operator/reconcile.go",
    "chars": 3022,
    "preview": "package operator\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\tctrl \"sigs.k8s.io/co"
  }
]

About this extraction

This page contains the full source code of the nekomeowww/ollama-operator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 124 files (996.0 KB), approximately 230.0k tokens, and a symbol index with 156 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!