Showing preview only (441K chars total). Download the full file or copy to clipboard to get everything.
Repository: bootc/netbox-chart
Branch: main
Commit: 96297979d1ba
Files: 79
Total size: 416.2 KB
Directory structure:
gitextract_jmg13inm/
├── .checkov.yaml
├── .editorconfig
├── .flake8
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.yml
│ ├── dependabot.yml
│ ├── renovate.json
│ └── workflows/
│ ├── analysis.yml
│ ├── auto-merge.yml
│ ├── ci.yml
│ ├── lint.yml
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── .markdownlint.yaml
├── LICENSE
├── README.md
├── charts/
│ ├── netbox/
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── README.md
│ │ ├── ci/
│ │ │ ├── default-values.yaml
│ │ │ ├── ingress-metrics-values.yaml
│ │ │ └── ldap-values.yaml
│ │ ├── docs/
│ │ │ ├── auth.md
│ │ │ ├── extra.md
│ │ │ ├── migrate.md
│ │ │ └── prod.md
│ │ ├── files/
│ │ │ ├── configuration.py
│ │ │ └── ldap_config.py
│ │ ├── templates/
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── configmap.yaml
│ │ │ ├── cronjob.yaml
│ │ │ ├── deployment.yaml
│ │ │ ├── extra-list.yaml
│ │ │ ├── granian-servicemonitor.yaml
│ │ │ ├── hpa.yaml
│ │ │ ├── httproute.yaml
│ │ │ ├── ingress.yaml
│ │ │ ├── pdb.yaml
│ │ │ ├── pvc.yaml
│ │ │ ├── role.yaml
│ │ │ ├── rolebinding.yaml
│ │ │ ├── secret.yaml
│ │ │ ├── service.yaml
│ │ │ ├── serviceaccount.yaml
│ │ │ ├── servicemonitor.yaml
│ │ │ ├── tests/
│ │ │ │ └── test-connection.yaml
│ │ │ └── worker/
│ │ │ ├── deployment.yaml
│ │ │ ├── hpa.yaml
│ │ │ └── pdb.yaml
│ │ ├── values.schema.json
│ │ └── values.yaml
│ └── netbox-operator/
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── README.md
│ ├── ci/
│ │ └── default-values.yaml
│ ├── crds/
│ │ ├── ipaddressclaims.yaml
│ │ ├── ipaddresses.yaml
│ │ ├── iprangeclaims.yaml
│ │ ├── ipranges.yaml
│ │ ├── prefixclaims.yaml
│ │ └── prefixes.yaml
│ ├── templates/
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── clusterrole.yaml
│ │ ├── clusterrolebinding.yaml
│ │ ├── deployment.yaml
│ │ ├── leaderelect/
│ │ │ ├── role.yaml
│ │ │ └── rolebinding.yaml
│ │ ├── secret.yaml
│ │ ├── serviceaccount.yaml
│ │ └── servicemonitor.yaml
│ └── values.yaml
├── config.yaml
└── pyproject.toml
================================================
FILE CONTENTS
================================================
================================================
FILE: .checkov.yaml
================================================
directory:
- charts
skip-path:
- /\w+/charts
evaluate-variables: true
framework:
- helm
compact: true
quiet: true
soft-fail: true
================================================
FILE: .editorconfig
================================================
# editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.py]
indent_size = 4
[*.md]
trim_trailing_whitespace = false
================================================
FILE: .flake8
================================================
[flake8]
max-line-length = 100
extend-ignore = E203, W503
per-file-ignores =
charts/netbox/files/*:E131,E251,E266,E302,E305,E501,E722,F821
================================================
FILE: .gitattributes
================================================
# https://git-scm.com/docs/gitattributes
# Auto detect text files and perform LF normalization
* text=auto eol=lf
# Collapse generated and vendored files on GitHub
*.lock linguist-generated=true merge=ours
# Reduce conflicts on markdown files
*.md merge=union
================================================
FILE: .github/FUNDING.yml
================================================
# https://docs.github.com/articles/displaying-a-sponsor-button-in-your-repository
github:
- RangerRick
- LeoColomb
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: 🐛 Bug Report
description: Create a report about a malfunction of the Helm chart setup
labels:
- bug
body:
- type: markdown
attributes:
value: |
> [!NOTE]
> This form is only for reporting _reproducible bugs_ in a current NetBox
> installation **using its Helm chart**.
> If you're looking for assistance with using NetBox, please visit our
> [discussion forum](https://github.com/netbox-community/netbox/discussions) instead.
> [!TIP]
> Please don't open an issue to open a PR. Just submit the PR, that's good enough.
- type: input
id: chart-version
attributes:
label: The Helm chart version
description: What version of the Helm chart are you running?
placeholder: netbox-5.0.0
validations:
required: true
- type: textarea
id: context-version
attributes:
label: Environment Versions
description: What version of relevant tools are you using?
render: text
placeholder: |
Kubernetes: 1.31
Helm: 3.12
FluxCD: 1.0
validations:
required: true
- type: textarea
id: chart-values-yml
attributes:
label: Custom chart values
description: Please provide your custom values (`values.yaml`)
render: yaml
placeholder: |
remoteAuth:
enabled: true
backends:
- netbox.authentication.RemoteUserBackend
ingress:
enabled: true
validations:
required: true
- type: textarea
id: current-behavior
attributes:
label: Current Behavior & Steps to Reproduce
description: Please describe what you did and how you think it misbehaved
placeholder: I tried to … by doing …, but it …
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: What did you expect to happen?
placeholder: I expected that … when I do …
validations:
required: true
- type: textarea
id: netbox-logs
attributes:
label: NetBox Logs
description: Please paste the output of the deploy Pod logs
render: text
placeholder: |
netbox_1 | ⚙️ Applying database migrations
netbox_1 | 🧬 loaded config '/etc/netbox/config/configuration.py'
netbox_1 | 🧬 loaded config '/etc/netbox/config/a.py'
netbox_1 | 🧬 loaded config '/etc/netbox/config/extra.py'
netbox_1 | 🧬 loaded config '/etc/netbox/config/logging.py'
netbox_1 | 🧬 loaded config '/etc/netbox/config/plugins.py'
...
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
blank_issues_enabled: false
contact_links:
- name: ❓ Question
url: https://github.com/netbox-community/netbox/discussions
about: The Github Discussions are the right place to ask questions about how to use or do certain things with NetBox.
- name: 💬 Community Slack
url: https://netdev.chat
about: "Join #netbox-chart on the NetDev Community Slack for assistance with installation issues and other problems."
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: ✨ Feature Request
description: Propose a new NetBox feature or enhancement
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
> [!NOTE]
> This form is only for submitting well-formed proposals to extend or modify
> NetBox **Helm charts** in some way.
> If you're trying to solve a problem but can't figure out how, or if
> you still need time to work on the details of a proposed new feature, please start a
> [discussion](https://github.com/netbox-community/netbox/discussions) instead.
- type: textarea
attributes:
label: Proposed functionality
description: |
Describe in detail the new feature or behavior you are proposing. Include any specific changes
to work flows, data models, and/or the user interface. The more detail you provide here, the
greater chance your proposal has of being discussed. Feature requests which don't include an
actionable implementation plan will be rejected.
validations:
required: true
- type: textarea
attributes:
label: Use case
description: |
Explain how adding this functionality would benefit NetBox users when using its Helm chart.
What need does it address?
validations:
required: true
================================================
FILE: .github/dependabot.yml
================================================
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
================================================
FILE: .github/renovate.json
================================================
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":configMigration",
":disableDependencyDashboard",
"customManagers:helmChartYamlAppVersions"
],
"labels": ["dependencies"],
"rangeStrategy": "bump",
"packageRules": [
{
"matchManagers": ["helmv3"],
"versioning": "helm"
},
{
"matchFileNames": ["charts/**"],
"bumpVersions": [
{
"filePatterns": ["{{packageFileDir}}/Chart.{yaml,yml}"],
"matchStrings": ["version:\\s(?<version>[^\\s]+)"],
"bumpType": "{{#if isMajor}}minor{{else}}patch{{/if}}"
}
]
},
{
"matchUpdateTypes": ["!major"],
"automerge": true
}
],
"kubernetes": {
"managerFilePatterns": ["/^charts/.+\\.ya?ml$/"]
},
"github-actions": {
"enabled": false
}
}
================================================
FILE: .github/workflows/analysis.yml
================================================
# https://docs.github.com/actions
name: Analysis
on:
push:
branches:
- main
pull_request:
branches:
- main
schedule:
- cron: "43 2 * * 6"
workflow_dispatch:
jobs:
checkov:
name: Checkov
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- uses: actions/checkout@v6.0.2
- name: Run Checkov scanner
id: checkov
uses: bridgecrewio/checkov-action@master
- name: Upload scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: results.sarif
================================================
FILE: .github/workflows/auto-merge.yml
================================================
# https://docs.github.com/actions
name: Auto-merge
on:
pull_request_target:
workflow_call:
permissions:
pull-requests: write
contents: write
jobs:
dependabot:
name: Dependabot
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' }}
steps:
- name: Dependabot metadata
id: dependabot-metadata
uses: dependabot/fetch-metadata@v3.1.0
- name: Approve a PR
if: steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major'
run: gh pr review --approve "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GITHUB_TOKEN: ${{ github.token }}
- name: Enable auto-merge for Dependabot PRs
run: gh pr merge --auto --rebase "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GITHUB_TOKEN: ${{ github.token }}
================================================
FILE: .github/workflows/ci.yml
================================================
# yamllint disable rule:document-start
# https://docs.github.com/actions
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
prepare:
name: Prepare
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.list-changed.outputs.changed }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Set up chart-testing
uses: helm/chart-testing-action@v2.8.0
- name: Run chart-testing (list-changed)
id: list-changed
run: |
changed=$(ct list-changed --config config.yaml)
if [[ -n "$changed" ]]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
test:
name: Test
if: needs.prepare.outputs.changed == 'true'
needs:
- prepare
uses: ./.github/workflows/test.yml
with:
action-matrix: '["lint-and-install", "install --upgrade"]'
secrets: inherit
results:
name: Status
if: always()
runs-on: ubuntu-latest
needs:
- prepare
- test
steps:
- run: exit 1
if: >-
${{
contains(needs.*.result, 'failure') ||
contains(needs.*.result, 'cancelled')
}}
release:
name: Release
if: github.ref == 'refs/heads/main'
uses: ./.github/workflows/release.yml
permissions:
contents: write
packages: write
id-token: write
secrets:
GPG_KEY_BASE64: ${{ secrets.GPG_KEY_BASE64 }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
================================================
FILE: .github/workflows/lint.yml
================================================
# https://docs.github.com/actions
name: Lint Code Base
on:
push:
branches-ignore: [main]
pull_request:
branches: [main]
permissions:
contents: read
packages: read
statuses: write
jobs:
build:
name: Lint Code Base
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v6.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Lint Code Base
uses: super-linter/super-linter/slim@9e863354e3ff62e0727d37183162c4a88873df41 # v8.6.0
env:
VALIDATE_ALL_CODEBASE: false
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FIX_MARKDOWN_PRETTIER: false
VALIDATE_BIOME_FORMAT: false
VALIDATE_MARKDOWN_PRETTIER: false
VALIDATE_JSCPD: false
VALIDATE_PYTHON_MYPY: false
VALIDATE_PYTHON_PYINK: false
FILTER_REGEX_EXCLUDE: charts/[^/]+/[^/]+/.*\.yaml
LINTER_RULES_PATH: /
PYTHON_BLACK_CONFIG_FILE: pyproject.toml
PYTHON_PYLINT_CONFIG_FILE: pyproject.toml
PYTHON_ISORT_CONFIG_FILE: pyproject.toml
PYTHON_RUFF_CONFIG_FILE: pyproject.toml
================================================
FILE: .github/workflows/release.yml
================================================
# yamllint disable rule:document-start
# https://docs.github.com/actions
name: Release
on:
workflow_call:
secrets:
GPG_KEY_BASE64:
required: true
description: GPG key for signing
GPG_PASSPHRASE:
required: true
description: passphrase for the signing key
jobs:
publish:
name: Publish
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Prepare GPG key
run: |
gpg_dir="${HOME}/.cr-gpg"
mkdir "$gpg_dir"
keyring="$gpg_dir/secring.gpg"
base64 -d <<< "$GPG_KEY_BASE64" > "$keyring"
passphrase_file="$gpg_dir/passphrase"
echo "$GPG_PASSPHRASE" > "$passphrase_file"
echo "CR_PASSPHRASE_FILE=$passphrase_file" >> "$GITHUB_ENV"
echo "CR_KEYRING=$keyring" >> "$GITHUB_ENV"
echo "GNUPGHOME=${gpg_dir}"
env:
GPG_KEY_BASE64: "${{ secrets.GPG_KEY_BASE64 }}"
GPG_PASSPHRASE: "${{ secrets.GPG_PASSPHRASE }}"
- name: Install Helm
uses: azure/setup-helm@v5.0.0
- name: Add Helm repos
run: helm repo add bitnami https://charts.bitnami.com/bitnami
- name: Run chart-releaser
uses: helm/chart-releaser-action@v1.7.0
with:
config: config.yaml
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push charts to GitHub Container Registry
run: |
shopt -s nullglob
for pkg in .cr-release-packages/*.tgz; do
if [ -z "${pkg:-}" ]; then
break
fi
helm push "${pkg}" "oci://ghcr.io/${GITHUB_REPOSITORY@L}"
done
================================================
FILE: .github/workflows/test.yml
================================================
# yamllint disable rule:document-start
# https://docs.github.com/actions
name: Test
on:
workflow_call:
inputs:
action-matrix:
required: false
default: '["install"]'
type: string
description: Matrix of actions to run
jobs:
ct:
name: Run chart-testing
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
action: ${{ fromJSON(inputs.action-matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Set up Helm
uses: azure/setup-helm@v5.0.0
- uses: actions/setup-python@v6
if: startsWith(matrix.action, 'lint')
with:
python-version: 3.x
- name: Set up chart-testing
uses: helm/chart-testing-action@v2.8.0
- name: Create kind cluster
uses: helm/kind-action@v1.14.0
if: contains(matrix.action, 'install')
- name: Run chart-testing (${{ matrix.action }})
run: ct ${{ matrix.action }} --config config.yaml --debug --helm-extra-set-args="$CT_HELM_EXTRA_SET_ARGS"
env:
CT_HELM_EXTRA_SET_ARGS: --set=host=${{ secrets.NETBOX_URL }} --set=auth.apiToken=${{ secrets.NETBOX_TOKEN }}
================================================
FILE: .gitignore
================================================
# https://git-scm.com/docs/gitignore
# General files
pkg/*
*.pyc
.project
/.bin
/_test/secrets/*.json
# macOS
._*
.DS_Store
# Editors and IDE
.idea/
.vscode/
*.swp
*.swo
# Emacs save files
*~
\#*\#
.\#*
# Vim-related files
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
# Releases
dist/
# Chart dependencies
**/charts/*.tgz
values-*.yaml
.history
/public
================================================
FILE: .markdownlint.yaml
================================================
default: true
MD013: false
MD031: false
MD060: false
================================================
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: README.md
================================================
# Netbox Helm Charts
> The official [Helm](https://helm.sh) charts repository for [Netbox](https://netbox.dev).
[](https://github.com/netbox-community/netbox-chart/actions/workflows/ci.yml)
[](https://artifacthub.io/packages/search?repo=netbox)
## About
This Git repository houses the official Helm charts for Netbox.
Do you have any questions?
Before opening an issue on GitHub, please join [our Slack](https://netdev.chat/)
and ask for help in the [`#netbox-chart`](https://netdev-community.slack.com/archives/C01Q6B100R2) channel.
| Chart | Version |
| :-------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| [`netbox/netbox`](charts/netbox/) | [](https://artifacthub.io/packages/helm/netbox/netbox) |
| [`netbox/netbox-operator`](charts/netbox-operator/) | [](https://artifacthub.io/packages/helm/netbox/netbox-operator) |
## Quickstart
```shell
helm install my-release oci://ghcr.io/netbox-community/netbox-chart/netbox
```
See docs on your preferred sources:
- [Charts docs on Artifact Hub](https://artifacthub.io/packages/search?org=netbox)
- [Charts respective readmes](charts)
- [Charts discovery](https://helm.sh/docs/helm/helm_search/)
```sh
helm search hub netbox
```
- [Charts repository](https://helm.sh/docs/helm/helm_repo/)
```sh
helm repo add netbox https://charts.netbox.oss.netboxlabs.com/
```
## License
This project is licensed under [Apache License, Version 2.0](LICENSE).
================================================
FILE: charts/netbox/.helmignore
================================================
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
# example production yaml
values-production.yaml
# ci files
ci/
# docs files
docs/
================================================
FILE: charts/netbox/Chart.yaml
================================================
apiVersion: v2
name: netbox
version: 8.2.7
# renovate: image=ghcr.io/netbox-community/netbox
appVersion: "v4.6.0"
type: application
kubeVersion: ^1.25.0-0
description: IP address management (IPAM) and data center infrastructure management (DCIM) tool
home: https://netbox.dev/
icon: https://raw.githubusercontent.com/netbox-community/netbox/main/docs/netbox_logo_light.svg
sources:
- https://github.com/netbox-community/netbox-chart
- https://github.com/netbox-community/netbox
maintainers:
- name: netbox-community
url: https://github.com/netbox-community
- name: bootc
url: https://github.com/bootc
dependencies:
- name: common
repository: oci://registry-1.docker.io/bitnamicharts
version: ^2.38.0
tags:
- bitnami-common
- name: postgresql
version: ^18.6.3
repository: oci://registry-1.docker.io/bitnamicharts
condition: postgresql.enabled
- name: valkey
version: ^5.6.1
repository: oci://registry-1.docker.io/bitnamicharts
condition: valkey.enabled
annotations:
artifacthub.io/images: |
- name: netbox
image: ghcr.io/netbox-community/netbox:v4.6.0
- name: busybox
image: docker.io/busybox:1.37.0
- name: kubectl
image: docker.io/rancher/kubectl:v1.36.0
artifacthub.io/license: Apache-2.0
artifacthub.io/links: |
- name: Upstream Project
url: https://github.com/netbox-community/netbox
artifacthub.io/changes: |
- kind: changed
description: New release
links:
- name: Changelog on GitHub Releases
url: https://github.com/netbox-community/netbox-chart/releases?q=netbox-
================================================
FILE: charts/netbox/README.md
================================================
# NetBox
[NetBox](https://netbox.dev) is an IP address management (IPAM) and
data center infrastructure management (DCIM) tool.
## TL;DR
```shell
helm install netbox oci://ghcr.io/netbox-community/netbox-chart/netbox
```
> [!tip]
> Please see [Production Considerations](docs/prod.md) guide before using this chart for real.
## Prerequisites
- Kubernetes [1.25+](https://kubernetes.io/releases/)
- Helm [3.10+](https://helm.sh/docs/topics/version_skew/)
## Installing the Chart
To install the chart with the release name `my-release` and default configuration:
```shell
helm install my-release oci://ghcr.io/netbox-community/netbox-chart/netbox
```
## Documentation
- [Production Considerations](docs/prod.md)
- [Authentication Options](docs/auth.md)
- [Extra Configuration](docs/extra.md)
- [Migration Guide](docs/migrate.md)
## Configuration
The following table lists the configurable parameters for this chart and their default values.
<!-- prettier-ignore-start -->
| Parameter | Description | Default |
| ------------------------------------------------|---------------------------------------------------------------------|----------------------------------------------|
| `global.imageRegistry` | Netbox and subchart image registry for pulling container images | `""` |
| `global.imagePullSecrets` | Netbox and subchart registry secret names as an array | `[]` |
| `global.storageClass` | Netbox and subchart default StorageClass for Persistent Volume(s) | `""` |
| `replicaCount` | The desired number of NetBox pods | `1` |
| `image.registry` | NetBox container image registry | `ghcr.io` |
| `image.repository` | NetBox container image repository | `netboxcommunity/netbox` |
| `image.tag` | NetBox container image tag | `""` |
| `image.pullPolicy` | NetBox container image pull policy | `IfNotPresent` |
| `superuser.name` | Initial super-user account to create | `admin` |
| `superuser.email` | Email address for the initial super-user account | `admin@example.com` |
| `superuser.password` | Password for the initial super-user account | `admin` |
| `superuser.apiToken` | API token created for the initial super-user account | `0123456789abcdef0123456789abcdef01234567` |
| `superuser.existingSecret` | Use an existing Kubernetes `Secret` for secret values | `""` |
| `allowedHosts` | List of valid FQDNs for this NetBox instance | `["*"]` |
| `admins` | List of admins to email about critical errors | `[]` |
| `allowTokenRetrieval` | Permit the retrieval of API tokens after their creation | `false` |
| `authPasswordValidators` | Configure validation of local user account passwords | `[]` |
| `allowedUrlSchemes` | URL schemes that are allowed within links in NetBox | *see `values.yaml`* |
| `banner.top` | Banner text to display at the top of every page | `""` |
| `banner.bottom` | Banner text to display at the bottom of every page | `""` |
| `banner.login` | Banner text to display on the login page | `""` |
| `basePath` | Base URL path if accessing NetBox within a directory | `""` |
| `changelogRetention` | Maximum number of days to retain logged changes (0 = forever) | `90` |
| `customValidators` | Custom validators for NetBox field values | `{}` |
| `defaultUserPreferences` | Default preferences for newly created user accounts | `{}` |
| `cors.originAllowAll` | [CORS]: allow all origins | `false` |
| `cors.originWhitelist` | [CORS]: list of origins authorised to make cross-site HTTP requests | `[]` |
| `cors.originRegexWhitelist` | [CORS]: list of regular expression matching authorised origins | `[]` |
| `csrf.cookieName` | Name of the CSRF authentication cookie | `csrftoken` |
| `csrf.trustedOrigins` | A list of trusted origins for unsafe (e.g. POST) requests | `[]` |
| `dataUploadMaxMemorySize` | The maximum size (in bytes) of an incoming HTTP request | `2621440` |
| `debug` | Enable NetBox debugging (NOT for production use) | `false` |
| `defaultLanguage` | Set the default preferred language/locale | `en-us` |
| `dbWaitDebug` | Show details of errors that occur when applying migrations | `false` |
| `email.server` | SMTP server to use to send emails | `localhost` |
| `email.port` | TCP port to connect to the SMTP server on | `25` |
| `email.username` | Optional username for SMTP authentication | `""` |
| `email.password` | Password for SMTP authentication (see also `existingSecret`) | `""` |
| `email.useSSL` | Use SSL when connecting to the server | `false` |
| `email.useTLS` | Use TLS when connecting to the server | `false` |
| `email.sslCertFile` | SMTP SSL certificate file path (e.g. in a mounted volume) | `""` |
| `email.sslKeyFile` | SMTP SSL key file path (e.g. in a mounted volume) | `""` |
| `email.timeout` | Timeout for SMTP connections, in seconds | `10` |
| `email.from` | Sender address for emails sent by NetBox | `""` |
| `enforceGlobalUnique` | Enforce unique IP space in the global table (not in a VRF) | `true` |
| `exemptViewPermissions` | A list of models to exempt from the enforcement of view permissions | `[]` |
| `fieldChoices` | Configure custom choices for certain built-in fields | `{}` |
| `fileUploadMaxMemorySize` | The maximum amount (in bytes) of uploaded data that will be held in memory before being written to the filesystem | `2621440` |
| `graphQlEnabled` | Enable the GraphQL API | `true` |
| `httpProxies` | HTTP proxies NetBox should use when sending outbound HTTP requests | `null` |
| `internalIPs` | IP addresses recognized as internal to the system | `['127.0.0.1', '::1']` |
| `jobRetention` | The number of days to retain job results (scripts and reports) | `90` |
| `logging` | Custom Django logging configuration | `{}` |
| `loginPersistence` | Enables users to remain authenticated to NetBox indefinitely | `false` |
| `loginRequired` | Permit only logged-in users to access NetBox | `false` (unauthenticated read-only access) |
| `loginTimeout` | How often to re-authenticate users | `1209600` (14 days) |
| `logoutRedirectUrl` | View name or URL to which users are redirected after logging out | `home` |
| `maintenanceMode` | Display a "maintenance mode" banner on every page | `false` |
| `mapsUrl` | The URL to use when mapping physical addresses or GPS coordinates | `https://maps.google.com/?q=` |
| `maxPageSize` | Maximum number of objects that can be returned by a single API call | `1000` |
| `storages` | `django-storages` backends configuration | `{}` |
| `paginateCount` | The default number of objects to display per page in the web UI | `50` |
| `plugins` | Additional plugins to load into NetBox | `[]` |
| `pluginsConfig` | Configuration for the additional plugins | `{}` |
| `powerFeedDefaultAmperage` | Default amperage value for new power feeds | `15` |
| `powerFeedMaxUtilisation` | Default maximum utilisation percentage for new power feeds | `80` |
| `powerFeedDefaultVoltage` | Default voltage value for new power feeds | `120` |
| `preferIPv4` | Prefer devices' IPv4 address when determining their primary address | `false` |
| `rackElevationDefaultUnitHeight` | Rack elevation default height in pixels | `22` |
| `rackElevationDefaultUnitWidth` | Rack elevation default width in pixels | `220` |
| `remoteAuth.enabled` | Enable remote authentication support | `false` |
| `remoteAuth.backends` | Remote authentication backend classes | `[netbox.authentication.RemoteUserBackend]` |
| `remoteAuth.header` | The name of the HTTP header which conveys the username | `HTTP_REMOTE_USER` |
| `remoteAuth.userFirstName` | HTTP header which contains the user's first name | `HTTP_REMOTE_USER_FIRST_NAME` |
| `remoteAuth.userLastName` | HTTP header which contains the user's last name | `HTTP_REMOTE_USER_LAST_NAME` |
| `remoteAuth.userEmail` | HTTP header which contains the user's email address | `HTTP_REMOTE_USER_EMAIL` |
| `remoteAuth.autoCreateUser` | Enables the automatic creation of new users | `false` |
| `remoteAuth.autoCreateGroups` | Enables the automatic creation of new groups | `false` |
| `remoteAuth.defaultGroups` | A list of groups to assign to newly created users | `[]` |
| `remoteAuth.defaultPermissions` | A list of permissions to assign newly created users | `{}` |
| `remoteAuth.groupSyncEnabled` | Sync remote user groups from an HTTP header set by a reverse proxy | `false` |
| `remoteAuth.groupHeader` | The name of the HTTP header which conveys the groups to which the user belongs | `HTTP_REMOTE_USER_GROUP` |
| `remoteAuth.superuserGroups` | The list of groups that promote an remote User to Superuser on login| `[]` |
| `remoteAuth.superusers` | The list of users that get promoted to Superuser on login | `[]` |
| `remoteAuth.staffGroups` | The list of groups that promote an remote User to Staff on login | `[]` |
| `remoteAuth.staffUsers` | The list of users that get promoted to Staff on login | `[]` |
| `remoteAuth.groupSeparator` | The Seperator upon which `remoteAuth.groupHeader` gets split into individual groups | `\|` |
| `remoteAuth.ldap.serverUri` | see [django-auth-ldap](https://django-auth-ldap.readthedocs.io) | `""` |
| `remoteAuth.ldap.startTls` | if StarTLS should be used | *see values.yaml* |
| `remoteAuth.ldap.ignoreCertErrors` | if Certificate errors should be ignored | *see values.yaml* |
| `remoteAuth.ldap.caCertDir` | CA certificate directory | *see auth.md* |
| `remoteAuth.ldap.caCertData` | CA certificate data | *see auth.md* |
| `remoteAuth.ldap.bindDn` | Distinguished Name to bind with | `""` |
| `remoteAuth.ldap.bindPassword` | Password for bind DN | `""` |
| `remoteAuth.ldap.userDnTemplate` | see [AUTH_LDAP_USER_DN_TEMPLATE](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-user-dn-template) | *see values.yaml* |
| `remoteAuth.ldap.userSearchBaseDn` | see base_dn of [django_auth_ldap.config.LDAPSearch](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#django_auth_ldap.config.LDAPSearch) | *see values.yaml* |
| `remoteAuth.ldap.userSearchAttr` | User attribute name for user search | `sAMAccountName` |
| `remoteAuth.ldap.groupSearchBaseDn` | base DN for group search | *see values.yaml* |
| `remoteAuth.ldap.groupSearchClass` | [django-auth-ldap](https://django-auth-ldap.readthedocs.io) for group search | `group` |
| `remoteAuth.ldap.groupType` | see [AUTH_LDAP_GROUP_TYPE](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-group-type) | `GroupOfNamesType` |
| `remoteAuth.ldap.requireGroupDn` | DN of a group that is required for login | `null` |
| `remoteAuth.ldap.findGroupPerms` | see [AUTH_LDAP_FIND_GROUP_PERMS](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-find-group-perms) | true |
| `remoteAuth.ldap.mirrorGroups` | see [AUTH_LDAP_MIRROR_GROUPS](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-mirror-groups) | `null` |
| `remoteAuth.ldap.cacheTimeout` | see [AUTH_LDAP_MIRROR_GROUPS_EXCEPT](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-mirror-groups-except) | `null` |
| `remoteAuth.ldap.isAdminDn` | required DN to be able to login in Admin-Backend, "is_staff"-Attribute of [AUTH_LDAP_USER_FLAGS_BY_GROUP](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-user-flags-by-group) | *see values.yaml* |
| `remoteAuth.ldap.isSuperUserDn` | required DN to receive SuperUser privileges, "is_superuser"-Attribute of [AUTH_LDAP_USER_FLAGS_BY_GROUP](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-user-flags-by-group) | *see values.yaml* |
| `remoteAuth.ldap.attrFirstName` | first name attribute of users, "first_name"-Attribute of [AUTH_LDAP_USER_ATTR_MAP](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-user-attr-map) | `givenName` |
| `remoteAuth.ldap.attrLastName` | last name attribute of users, "last_name"-Attribute of [AUTH_LDAP_USER_ATTR_MAP](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-user-attr-map) | `sn` |
| `remoteAuth.ldap.attrMail` | mail attribute of users, "email_name"-Attribute of [AUTH_LDAP_USER_ATTR_MAP](https://django-auth-ldap.readthedocs.io/en/latest/reference.html#auth-ldap-user-attr-map) | `mail` |
| `releaseCheck.url` | Release check URL (GitHub API URL; see `values.yaml`) | `null` (disabled by default) |
| `rqDefaultTimeout` | Maximum execution time for background tasks, in seconds | `300` (5 minutes) |
| `sessionCookieName` | The name to use for the session cookie | `"sessionid"` |
| `enableLocalization` | Localization | `false` |
| `timeZone` | The time zone NetBox will use when dealing with dates and times | `UTC` |
| `dateFormat` | Django date format for long-form date strings | `"N j, Y"` |
| `shortDateFormat` | Django date format for short-form date strings | `"Y-m-d"` |
| `timeFormat` | Django date format for long-form time strings | `"g:i a"` |
| `metrics.granian.enabled` | Enable Granian metrics | `true` |
| `metrics.granian.serviceMonitor.enabled` | Whether to enable a [ServiceMonitor](https://prometheus-operator.dev/docs/operator/design/#servicemonitor) for Granian metrics | `false` |
| `metrics.granian.serviceMonitor.additionalLabels`| Additonal labels to apply to the ServiceMonitor | `{}` |
| `metrics.granian.serviceMonitor.honorLabels` | honorLabels chooses the metric's labels on collisions | `false` |
| `metrics.granian.serviceMonitor.interval` | Interval at which metrics should be scraped | `""` |
| `metrics.granian.serviceMonitor.scrapeTimeout` | Timeout duration for scraping metrics | `""` |
| `metrics.granian.serviceMonitor.metricRelabelings`| Specify additional relabeling of metrics | `[]` |
| `metrics.granian.serviceMonitor.relabelings` | Specify general relabeling | `[]` |
| `metrics.granian.serviceMonitor.selector` | Prometheus instance selector labels | `{}` |
| `metrics.enabled` | Expose Prometheus metrics at the `/metrics` HTTP endpoint | `false` |
| `metrics.serviceMonitor.enabled` | Whether to enable a [ServiceMonitor](https://prometheus-operator.dev/docs/operator/design/#servicemonitor) for Netbox | `false` |
| `metrics.serviceMonitor.additionalLabels` | Additonal labels to apply to the ServiceMonitor | `{}` |
| `metrics.serviceMonitor.honorLabels` | honorLabels chooses the metric's labels on collisions | `false` |
| `metrics.serviceMonitor.interval` | Interval at which metrics should be scraped | `""` |
| `metrics.serviceMonitor.scrapeTimeout` | Timeout duration for scraping metrics | `""` |
| `metrics.serviceMonitor.metricRelabelings` | Specify additional relabeling of metrics | `[]` |
| `metrics.serviceMonitor.relabelings` | Specify general relabeling | `[]` |
| `metrics.serviceMonitor.selector` | Prometheus instance selector labels | `{}` |
| `shortTimeFormat` | Django date format for short-form time strings | `"H:i:s"` |
| `dateTimeFormat` | Django date format for long-form date and time strings | `"N j, Y g:i a"` |
| `shortDateTimeFormat` | Django date format for short-form date and time strongs | `"Y-m-d H:i"` |
| `extraConfig` | Additional NetBox configuration (see `values.yaml`) | `[]` |
| `secretKey` | Django secret key used for sessions and password reset tokens | `""` (generated) |
| `existingSecret` | Use an existing Kubernetes `Secret` for secret values (see below) | `""` (use individual chart values) |
| `postgresql.enabled` | Deploy PostgreSQL using bundled Bitnami PostgreSQL chart | `true` |
| `postgresql.auth.username` | Username to create for NetBox in bundled PostgreSQL instance | `netbox` |
| `postgresql.auth.database` | Database to create for NetBox in bundled PostgreSQL instance | `netbox` |
| `postgresql.*` | Values under this key are passed to the bundled PostgreSQL chart | n/a |
| `externalDatabase.host` | PostgreSQL host to use when `postgresql.enabled` is `false` | `localhost` |
| `externalDatabase.port` | Port number for external PostgreSQL | `5432` |
| `externalDatabase.database` | Database name for external PostgreSQL | `netbox` |
| `externalDatabase.username` | Username for external PostgreSQL | `netbox` |
| `externalDatabase.password` | Password for external PostgreSQL (see also `existingSecret`) | `""` |
| `externalDatabase.existingSecretName` | Fetch password for external PostgreSQL from a different `Secret` | `""` |
| `externalDatabase.existingSecretKey` | Key to fetch the password in the above `Secret` | `postgresql-password` |
| `externalDatabase.connMaxAge` | The lifetime of a database connection, as an integer of seconds | `300` |
| `externalDatabase.disableServerSideCursors` | Disable the use of server-side cursors transaction pooling | `false` |
| `externalDatabase.options` | Additional PostgreSQL client parameters | `{}` |
| `valkey.enabled` | Deploy Valkey using bundled Bitnami Valkey chart | `true` |
| `valkey.*` | Values under this key are passed to the bundled Valkey chart | n/a |
| `tasksDatabase.database` | KV database number used for NetBox task queue | `0` |
| `tasksDatabase.ssl` | Enable SSL when connecting to KV | `false` |
| `tasksDatabase.insecureSkipTlsVerify` | Skip TLS certificate verification when connecting to KV | `false` |
| `tasksDatabase.caCertPath` | Path to CA certificates bundle for KV (needs mounting manually) | `""` |
| `tasksDatabase.host` | KV host to use when `valkey.enabled` is `false` | `"netbox-kv"` |
| `tasksDatabase.port` | Port number for external KV | `6379` |
| `tasksDatabase.sentinels` | List of sentinels in `host:port` form (`host` and `port` not used) | `[]` |
| `tasksDatabase.sentinelService` | Sentinel master service name | `"netbox-kv"` |
| `tasksDatabase.sentinelTimeout` | Sentinel connection timeout, in seconds | `300` (5 minutes) |
| `tasksDatabase.username` | Username for external KV | `""` |
| `tasksDatabase.password` | Password for external KV (see also `existingSecret`) | `""` |
| `tasksDatabase.existingSecretName` | Fetch password for external KV from a different `Secret` | `""` |
| `tasksDatabase.existingSecretKey` | Key to fetch the password in the above `Secret` | `tasks-password` |
| `cachingDatabase.database` | KV database number used for caching views | `1` |
| `cachingDatabase.ssl` | Enable SSL when connecting to KV | `false` |
| `cachingDatabase.insecureSkipTlsVerify` | Skip TLS certificate verification when connecting to KV | `false` |
| `cachingDatabase.caCertPath` | Path to CA certificates bundle for KV (needs mounting manually) | `""` |
| `cachingDatabase.host` | KV host to use when `valkey.enabled` is `false` | `"netbox-kv"` |
| `cachingDatabase.port` | Port number for external KV | `6379` |
| `cachingDatabase.sentinels` | List of sentinels in `host:port` form (`host` and `port` not used) | `[]` |
| `cachingDatabase.sentinelService` | Sentinel master service name | `"netbox-kv"` |
| `cachingDatabase.sentinelTimeout` | Sentinel connection timeout, in seconds | `300` (5 minutes) |
| `cachingDatabase.username` | Username for external KV | `""` |
| `cachingDatabase.password` | Password for external KV (see also `existingSecret`) | `""` |
| `cachingDatabase.existingSecretName` | Fetch password for external KV from a different `Secret` | `""` |
| `cachingDatabase.existingSecretKey` | Key to fetch the password in the above `Secret` | `cache-password` |
| `imagePullSecrets` | List of `Secret` names containing private registry credentials | `[]` |
| `nameOverride` | Override the application name (`netbox`) used throughout the chart | `""` |
| `fullnameOverride` | Override the full name of resources created as part of the release | `""` |
| `serviceAccount.create` | Create a ServiceAccount for NetBox | `true` |
| `serviceAccount.annotations` | Annotations to add to the service account | `{}` |
| `serviceAccount.name` | The name of the service account to use | `""` (use the fullname) |
| `serviceAccount.imagePullSecrets` | Add an imagePullSecrets attribute to the serviceAccount | `""` |
| `serviceAccount.automountServiceAccountToken` | Whether to automatically mount the token in the containers using this serviceAccount or not | `false` |
| `persistence.enabled` | Enable storage persistence for uploaded media (images) | `true` |
| `persistence.existingClaim` | Use an existing `PersistentVolumeClaim` instead of creating one | `""` |
| `persistence.subPath` | Mount a sub-path of the volume into the container, not the root | `""` |
| `persistence.storageClass` | Set the storage class of the PVC (use `-` to disable provisioning) | `""` |
| `persistence.selector` | Set the selector for PVs, if desired | `{}` |
| `persistence.accessMode` | Access mode for the volume | `ReadWriteOnce` |
| `persistence.size` | Size of persistent volume to request | `1Gi` |
| `reportsPersistence.enabled` | Enable storage persistence for NetBox reports | `false` |
| `reportsPersistence.existingClaim` | Use an existing `PersistentVolumeClaim` instead of creating one | `""` |
| `reportsPersistence.subPath` | Mount a sub-path of the volume into the container, not the root | `""` |
| `reportsPersistence.storageClass` | Set the storage class of the PVC (use `-` to disable provisioning) | `""` |
| `reportsPersistence.selector` | Set the selector for PVs, if desired | `{}` |
| `reportsPersistence.accessMode` | Access mode for the volume | `ReadWriteOnce` |
| `reportsPersistence.size` | Size of persistent volume to request | `1Gi` |
| `scriptsPersistence.enabled` | Enable storage persistence for NetBox reports | `false` |
| `scriptsPersistence.existingClaim` | Use an existing `PersistentVolumeClaim` instead of creating one | `""` |
| `scriptsPersistence.subPath` | Mount a sub-path of the volume into the container, not the root | `""` |
| `scriptsPersistence.storageClass` | Set the storage class of the PVC (use `-` to disable provisioning) | `""` |
| `scriptsPersistence.selector` | Set the selector for PVs, if desired | `{}` |
| `scriptsPersistence.accessMode` | Access mode for the volume | `ReadWriteOnce` |
| `scriptsPersistence.size` | Size of persistent volume to request | `1Gi` |
| `podAnnotations` | Additional annotations for NetBox pods | `{}` |
| `podLabels` | Additional labels for NetBox pods | `{}` |
| `podSecurityContext` | Security context for NetBox pods | *see `values.yaml`* |
| `securityContext` | Security context for NetBox containers | *see `values.yaml`* |
| `service.type` | Type of `Service` resource to create | `ClusterIP` |
| `service.port` | Port number for the service | `80` |
| `service.nodePort` | The port used on the node when `service.type` is NodePort | `""` |
| `service.clusterIP` | The cluster IP address assigned to the service | `""` |
| `service.clusterIPs` | A list of cluster IP addresses assigned to the service | `[]` |
| `service.externalIPs` | A list of external IP addresses aliased to this service | `[]` |
| `service.externalTrafficPolicy` | Policy for routing external traffic | `Cluster` |
| `service.ipFamilyPolicy` | Represents the dual-stack-ness of the service | `""` |
| `service.loadBalancerIP` | Request a specific IP address when `service.type` is `LoadBalancer` | `""` |
| `service.loadBalancerSourceRanges` | A list of allowed IP ranges when `service.type` is `LoadBalancer` | `[]` |
| `service.loadBalancerClass` | Load Balancer class if `service.type` is `LoadBalancer` | `""` |
| `service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` |
| `service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` |
| `ingress.enabled` | Create an `Ingress` resource for accessing NetBox | `false` |
| `ingress.className` | Use a named IngressClass | `""` |
| `ingress.annotations` | Extra annotations to apply to the `Ingress` resource | `{}` |
| `ingress.hosts` | List of hosts and paths to map to the service (see `values.yaml`) | `[{host:"chart-example.local",paths:["/"]}]` |
| `ingress.tls` | TLS settings for the `Ingress` resource | `[]` |
| `httpRoute.enabled` | Create an `HTTPRoute` resource for Gateway API | `false` |
| `httpRoute.annotations` | Extra annotations to apply to the `HTTPRoute` resource | `{}` |
| `httpRoute.parentRefs` | References to the parent Gateway(s) for the `HTTPRoute` | `[]` |
| `httpRoute.hostnames` | Hostnames that the `HTTPRoute` should match | `[]` |
| `httpRoute.filters` | Optional filters to apply to the route | `[]` |
| `resources` | Configure resource requests or limits for NetBox | `{}` |
| `automountServiceAccountToken` | Whether to automatically mount the serviceAccount token in the main container or not | `false` |
| `priorityClassName` | Pods' priorityClassName | `""` |
| `schedulerName` | Name of the k8s scheduler (other than default) for pods | `""` |
| `terminationGracePeriodSeconds` | Seconds pods need to terminate gracefully | `""` |
| `topologySpreadConstraints` | Configure Pod Topology Spread Constraints for NetBox | `[]` |
| `livenessProbe.enabled` | Enable Kubernetes livenessProbe, see [liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-liveness-command) | *see `values.yaml`* |
| `livenessProbe.initialDelaySeconds` | Number of seconds | *see `values.yaml`* |
| `livenessProbe.timeoutSeconds` | Number of seconds | *see `values.yaml`* |
| `livenessProbe.periodSeconds` | Number of seconds | *see `values.yaml`* |
| `livenessProbe.successThreshold` | Number of seconds | *see `values.yaml`* |
| `readinessProbe.enabled` | Enable Kubernetes readinessProbe, see [readiness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes) | *see `values.yaml`* |
| `readinessProbe.initialDelaySeconds` | Number of seconds | *see `values.yaml`* |
| `readinessProbe.timeoutSeconds` | Number of seconds | *see `values.yaml`* |
| `readinessProbe.periodSeconds` | Number of seconds | *see `values.yaml`* |
| `readinessProbe.successThreshold` | Number of seconds | *see `values.yaml`* |
| `lifecycleHooks` | Automate configuration before or after container startup | `{}` |
| `startupProbe.enabled` | Enable Kubernetes startupProbe, see [startup probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes) | *see `values.yaml`* |
| `startupProbe.initialDelaySeconds` | Number of seconds | *see `values.yaml`* |
| `startupProbe.timeoutSeconds` | Number of seconds | *see `values.yaml`* |
| `startupProbe.periodSeconds` | Number of seconds | *see `values.yaml`* |
| `startupProbe.successThreshold` | Number of seconds | *see `values.yaml`* |
| `init.image.registry` | Init container image registry | `ghcr.io` |
| `init.image.repository` | Init container image repository | `busybox` |
| `init.image.tag` | Init container image tag | `1.37.0` |
| `init.image.pullPolicy` | Init container image pull policy | `IfNotPresent` |
| `init.resourcesPreset` | Configure a preset for requests or limits for init container | `nano` |
| `init.resources` | Configure resource requests or limits for init container | `{}` |
| `init.securityContext` | Security context for init container | *see `values.yaml`* |
| `test.image.registry` | Test container image registry | `ghcr.io` |
| `test.image.repository` | Test container image repository | `busybox` |
| `test.image.tag` | Test container image tag | `1.37.0` |
| `test.image.pullPolicy` | Test container image pull policy | `IfNotPresent` |
| `test.resourcesPreset` | Configure a preset for requests or limits for test container | `nano` |
| `test.resources` | Configure resource requests or limits for test container | `{}` |
| `test.securityContext` | Security context for test container | *see `values.yaml`* |
| `autoscaling.enabled` | Whether to enable the HorizontalPodAutoscaler | `false` |
| `autoscaling.minReplicas` | Minimum number of replicas when autoscaling is enabled | `1` |
| `autoscaling.maxReplicas` | Maximum number of replicas when autoscaling is enabled | `100` |
| `autoscaling.targetCPUUtilizationPercentage` | Target CPU utilisation percentage for autoscaling | `80` |
| `autoscaling.targetMemoryUtilizationPercentage` | Target memory utilisation percentage for autoscaling | `null` |
| `autoscaling.behavior` | HPA behavior (scaleUp/scaleDown policies and settings) | `{}` |
| `nodeSelector` | Node labels for pod assignment | `{}` |
| `tolerations` | Toleration labels for pod assignment | `[]` |
| `updateStrategy` | Configure deployment update strategy | `{}` (defaults to `RollingUpdate`) |
| `affinity` | Affinity settings for pod assignment | `{}` |
| `extraEnvs` | Additional environment variables to set in the NetBox container | `[]` |
| `extraVolumeMounts` | Additional volumes to mount in the NetBox container | `[]` |
| `extraVolumes` | Additional volumes to reference in pods | `[]` |
| `sidecars` | Additional sidecar containers to be added to pods | `[]` |
| `initContainers` | Additional init containers to run before starting main containers | `[]` |
| `command` | NetBox container custom command/entrypoint | `[]` |
| `args` | NetBox container custom args | `[]` |
| `worker` | Worker specific variables. Most global variables also apply here. | *see `values.yaml`* |
| `housekeeping.enabled` | Whether the [Housekeeping][housekeeping] `CronJob` should be active | `true` |
| `housekeeping.concurrencyPolicy` | ConcurrencyPolicy for the Housekeeping CronJob. | `Forbid` |
| `housekeeping.failedJobsHistoryLimit` | Number of failed jobs to keep in history | `5` |
| `housekeeping.command` | The shell command to execute in the housekeeping job. | `[/opt/netbox/venv/bin/python, /opt/netbox/netbox/manage.py, housekeeping]`|
| `housekeeping.args` | NetBox housekeeping container custom args | `[]` |
| `housekeeping.restartPolicy` | Restart Policy for the Housekeeping CronJob. | `OnFailure` |
| `housekeeping.schedule` | Schedule for the CronJob in [Cron syntax][cron syntax]. | `0 0 * * *` (Midnight daily) |
| `housekeeping.successfulJobsHistoryLimit` | Number of successful jobs to keep in history | `5` |
| `housekeeping.suspend` | Whether to suspend the CronJob | `false` |
| `housekeeping.podAnnotations` | Additional annotations for housekeeping CronJob pods | `{}` |
| `housekeeping.podLabels` | Additional labels for housekeeping CronJob pods | `{}` |
| `housekeeping.podSecurityContext` | Security context for housekeeping CronJob pods | *see `values.yaml`* |
| `housekeeping.securityContext` | Security context for housekeeping CronJob containers | *see `values.yaml`* |
| `housekeeping.automountServiceAccountToken` | Whether to automatically mount the serviceAccount token in the housekeeping container or not | `false` |
| `housekeeping.resources` | Configure resource requests or limits for housekeeping CronJob | `{}` |
| `housekeeping.nodeSelector` | Node labels for housekeeping CronJob pod assignment | `{}` |
| `housekeeping.tolerations` | Toleration labels for housekeeping CronJob pod assignment | `[]` |
| `housekeeping.affinity` | Affinity settings for housekeeping CronJob pod assignment | `{}` |
| `housekeeping.extraEnvs` | Additional environment variables to set in housekeeping CronJob | `[]` |
| `housekeeping.extraVolumeMounts` | Additional volumes to mount in the housekeeping CronJob | `[]` |
| `housekeeping.extraVolumes` | Additional volumes to reference in housekeeping CronJob pods | `[]` |
| `housekeeping.sidecars` | Additional sidecar containers to be added to housekeeping CronJob | `[]` |
| `housekeeping.initContainers` | Additional init containers for housekeeping CronJob pods | `[]` |
<!-- prettier-ignore-end -->
[CORS]: https://github.com/ottoyiu/django-cors-headers
[housekeeping]: https://netboxlabs.com/docs/netbox/en/stable/administration/housekeeping/
[cron syntax]: https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-schedule-syntax
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install` or provide a YAML file containing the values for the above parameters:
```shell
helm install my-release --devel --values values.yaml \
oci://ghcr.io/netbox-community/netbox-chart/netbox
```
## Persistent storage pitfalls
Persistent storage for media is enabled by default, but unless you take special
care you will run into issues. The most common issue is that one of the NetBox
pods gets stuck in the `ContainerCreating` state. There are several ways around
this problem:
<!-- prettier-ignore-start -->
1. Use the recommended S3 `storages` and **disable** persistent storage
by setting `persistence.enabled` to `false`. This can
be used with any S3-compatible storage provider including Amazon S3, Minio,
Ceph RGW, and many others. See further down for an example of this.
2. Use a `ReadWriteMany` volume that can be mounted by several pods across
nodes simultaneously.
3. Configure pod affinity settings to keep all the pods on the same node. This
allows a `ReadWriteOnce` volume to be mounted in several pods at the same
time.
4. Disable persistent storage of media altogether and just manage without. The
storage functionality is only needed to store uploaded image attachments.
<!-- prettier-ignore-end -->
To configure the pod affinity to allow using a `ReadWriteOnce` volume you can
use the following example configuration:
```yaml
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: netbox
topologyKey: kubernetes.io/hostname
housekeeping:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: netbox
topologyKey: kubernetes.io/hostname
worker:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: netbox
topologyKey: kubernetes.io/hostname
```
## Using an Existing Secret
Rather than specifying passwords and secrets as part of the Helm release values,
you may pass these to NetBox using pre-existing `Secret` resources. When using
this, the respective `Secret`s must contain the following keys.
### Superuser secret (`superuser.existingSecret`)
Type: `kubernetes.io/basic-auth`
| Key | Description | Required? |
| ----------- | ---------------------------------------------------- | --------- |
| `username` | Username for the initial super-user account | Yes |
| `password` | Password for the initial super-user account | Yes |
| `email` | Email address for the initial super-user account | Yes |
| `api_token` | API token created for the initial super-user account | Yes |
### Config secret (`existingSecret`)
| Key | Description | Required? |
| -------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `ldap_bind_password` | Password for LDAP bind DN | If `remoteAuth.enabled` is `true` and `remoteAuth.backend` is `netbox.authentication.LDAPBackend` |
| `secret_key` | Django secret key used for sessions and password reset tokens | Yes |
### Email secret (`email.existingSecretName`)
| Key | Description | Required? |
| -------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `email-password` | SMTP user password | Yes, but the value may be left blank if not required |
### PostgreSQL secret (`externalDatabase.existingSecretName`)
| Key | Description | Required? |
| --------------------- | ------------------------------------------------- | ---------------------------------- |
| `postgresql-password` | The password for the external PostgreSQL database | If `postgresql.enabled` is `false` |
### Tasks secrets (`tasksDatabase.existingSecretName`)
| Key | Description | Required? |
| ---------------- | ------------------------------------------------------------- | ----------------------------- |
| `tasks-password` | Password for the external KV database (tasks and/or cache) | If `valkey.enabled` is `false` |
### Cache secrets (`cachingDatabase.existingSecretName`)
| Key | Description | Required? |
| ---------------- | ------------------------------------------------------------- | ----------------------------- |
| `cache-password` | Password for the external KV database (tasks and/or cache) | If `valkey.enabled` is `false` |
## License
This project is licensed under [Apache License, Version 2.0](LICENSE).
================================================
FILE: charts/netbox/ci/default-values.yaml
================================================
================================================
FILE: charts/netbox/ci/ingress-metrics-values.yaml
================================================
ingress:
enabled: true
metrics:
enabled: true
================================================
FILE: charts/netbox/ci/ldap-values.yaml
================================================
remoteAuth:
enabled: true
backends:
- netbox.authentication.LDAPBackend
ldap:
serverUri: "ldap://ldap.forumsys.com"
startTls: true
ignoreCertErrors: true
caCertData: ""
bindDn: "cn=read-only-admin,dc=example,dc=com"
bindPassword: password
userDnTemplate: ""
userSearchBaseDn: "dc=example,dc=com"
userSearchAttr: "sAMAccountName"
groupSearchBaseDn: "dc=example,dc=com"
groupSearchClass: "group"
groupType: "GroupOfNamesType"
requireGroupDn:
- "cn=read-only-admin,dc=example,dc=com"
findGroupPerms: true
mirrorGroups: true
mirrorGroupsExcept: ""
cacheTimeout: 3600
isAdminDn:
- "ou=mathematicians,cn=read-only-admin,dc=example,dc=com"
isSuperUserDn:
- "ou=scientists,cn=read-only-admin,dc=example,dc=com"
attrFirstName: "givenName"
attrLastName: "sn"
attrMail: "mail"
================================================
FILE: charts/netbox/docs/auth.md
================================================
# Authentication Options
## Using SSO
You can configure different SSO backends with `remoteAuth`.
The implementation is based on [Python Social Auth](https://python-social-auth.readthedocs.io/en/latest/backends/index.html#supported-backends).
Depending on the chosen backend you may need to configure different parameters.
You can leverage the `extraConfig` value in conjunction with `remoteAuth`.
> [!tip]
> Read more about `extraConfig` usage within [Extra Configuration](./extra.md) guide.
By default the users do not have any permission after logging in.
Using custom auth pipelines you can assign groups based on the roles supplied by the oauth provider.
### Example config for Keycloak backend
```yaml
remoteAuth:
enabled: true
backends:
- social_core.backends.keycloak.KeycloakOAuth2
autoCreateUser: true
extraConfig:
- secret:
secretName: keycloak-client
- values:
SOCIAL_AUTH_PIPELINE:
[
"social_core.pipeline.social_auth.social_details",
"social_core.pipeline.social_auth.social_uid",
"social_core.pipeline.social_auth.social_user",
"social_core.pipeline.user.get_username",
"social_core.pipeline.social_auth.associate_by_email",
"social_core.pipeline.user.create_user",
"social_core.pipeline.social_auth.associate_user",
"netbox.authentication.user_default_groups_handler",
"social_core.pipeline.social_auth.load_extra_data",
"social_core.pipeline.user.user_details",
"netbox.sso_pipeline_roles.set_role",
]
extraVolumes:
- name: sso-pipeline-roles
configMap:
name: sso-pipeline-roles
extraVolumeMounts:
- name: sso-pipeline-roles
mountPath: /opt/netbox/netbox/netbox/sso_pipeline_roles.py
subPath: sso_pipeline_roles.py
readOnly: true
```
Additional resources are necessary:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: keycloak-client
namespace: netbox
type: Opaque
data:
oidc-keycloak.yaml: |
SOCIAL_AUTH_KEYCLOAK_KEY: <OAUTH_CLIENT_ID>
SOCIAL_AUTH_KEYCLOAK_SECRET: <OAUTH_CLIENT_SECRET>
SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY: MIIB...AB
SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL: "https://keycloak.example.com/auth/realms/master/protocol/openid-connect/auth"
SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL: "https://keycloak.example.com/auth/realms/master/protocol/openid-connect/token"
SOCIAL_AUTH_JSONFIELD_ENABLED: true
SOCIAL_AUTH_STAFF_ROLE: staff
SOCIAL_AUTH_SUPERUSER_ROLE: superuser
---
apiVersion: v1
kind: ConfigMap
metadata:
name: sso-pipeline-roles
namespace: netbox
data:
sso_pipeline_roles.py: |
from django.conf import settings
from netbox.authentication import Group
def set_role(response, user, backend, *args, **kwargs):
client_id = getattr(settings, 'SOCIAL_AUTH_KEYCLOAK_KEY', None)
staff_role = getattr(settings, 'SOCIAL_AUTH_STAFF_ROLE', 'staff')
superuser_role = getattr(settings, 'SOCIAL_AUTH_SUPERUSER_ROLE', 'superuser')
roles = []
try:
roles = response['resource_access'][client_id]['roles']
except KeyError:
pass
user.is_staff = (staff_role in roles)
user.is_superuser = (superuser_role in roles)
user.save()
groups = Group.objects.all()
for group in groups:
try:
if group.name in roles:
group.users.add(user)
else:
group.users.remove(user)
except Group.DoesNotExist:
continue
```
> [!note]
> A hardcoded custom audience mapper is required on Keycloak.
>
> For the audience name to be in the token, enter the Client ID
> in the _Included **Custom** Audience_ field instead of the _Included **Client** Audience_ field.
>
> Refer to the Keycloak usage materials:
>
> - [Python Social Auth Documentation](https://python-social-auth.readthedocs.io/en/latest/backends/keycloak.html)
> - [Python Social Auth Source Code](https://github.com/python-social-auth/social-core/blob/d9554fa40e751c85ae60231fe2f5bd5a528c4452/social_core/backends/keycloak.py#L7-L96)
> - [Keycloak Documentation](https://www.keycloak.org/docs/latest/server_admin/#_audience_hardcoded)
### Example config for GitLab backend
```yaml
remoteAuth:
enabled: true
backends:
- social_core.backends.gitlab.GitLabOAuth2
autoCreateUser: true
extraConfig:
- secret:
secretName: gitlab-client
- values:
SOCIAL_AUTH_PIPELINE:
[
"social_core.pipeline.social_auth.social_details",
"social_core.pipeline.social_auth.social_uid",
"social_core.pipeline.social_auth.social_user",
"social_core.pipeline.user.get_username",
"social_core.pipeline.social_auth.associate_by_email",
"social_core.pipeline.user.create_user",
"social_core.pipeline.social_auth.associate_user",
"netbox.authentication.user_default_groups_handler",
"social_core.pipeline.social_auth.load_extra_data",
"social_core.pipeline.user.user_details",
"netbox.sso_pipeline_roles.set_role",
]
extraVolumes:
- name: sso-pipeline-roles
configMap:
name: sso-pipeline-roles
extraVolumeMounts:
- name: sso-pipeline-roles
mountPath: /opt/netbox/netbox/netbox/sso_pipeline_roles.py
subPath: sso_pipeline_roles.py
readOnly: true
```
Additional resources are necessary (please note that the client ID is necessary in the custom pipeline script):
```yaml
apiVersion: v1
kind: Secret
metadata:
name: gitlab-client
namespace: netbox
type: Opaque
stringData:
oidc-gitlab.yaml: |
SOCIAL_AUTH_GITLAB_API_URL: https://git.example.com
SOCIAL_AUTH_GITLAB_AUTHORIZATION_URL: https://git.example.com/oauth/authorize
SOCIAL_AUTH_GITLAB_ACCESS_TOKEN_URL: https://git.example.com/oauth/token
SOCIAL_AUTH_GITLAB_KEY: <OAUTH_CLIENT_ID>
SOCIAL_AUTH_GITLAB_SECRET: <OAUTH_CLIENT_SECRET>
SOCIAL_AUTH_GITLAB_SCOPE: ['read_user', 'openid']
SOCIAL_AUTH_STAFF_ROLE: staff
SOCIAL_AUTH_SUPERUSER_ROLE: superuser
---
apiVersion: v1
kind: ConfigMap
metadata:
name: sso-pipeline-roles
namespace: netbox
data:
sso_pipeline_roles.py: |
from django.conf import settings
from netbox.authentication import Group
import jwt
from jwt import PyJWKClient
def set_role(response, user, backend, *args, **kwargs):
client_id = getattr(settings, 'SOCIAL_AUTH_GITLAB_KEY', None)
staff_role = getattr(settings, 'SOCIAL_AUTH_STAFF_ROLE', 'staff')
superuser_role = getattr(settings, 'SOCIAL_AUTH_SUPERUSER_ROLE', 'superuser')
jwks_client = PyJWKClient("https://git.example.com/oauth/discovery/keys")
signing_key = jwks_client.get_signing_key_from_jwt(response['id_token'])
decoded = jwt.decode(
response['id_token'],
signing_key.key,
algorithms=["RS256"],
audience=client_id,
)
roles = []
try:
roles = decoded.get('groups_direct')
except KeyError:
pass
user.is_staff = (staff_role in roles)
user.is_superuser = (superuser_role in roles)
user.save()
groups = Group.objects.all()
for group in groups:
try:
if group.name in roles:
group.users.add(user)
else:
group.users.remove(user)
except Group.DoesNotExist:
continue
```
## Using LDAP Authentication
In order to enable LDAP authentication, please carry out the following steps:
1. Configure the `remoteAuth` settings to enable the LDAP backend (see below)
2. Make sure you set _all_ of the `remoteAuth.ldap` settings shown in the `values.yaml` file
For example:
```yaml
remoteAuth:
enabled: true
backends:
- netbox.authentication.LDAPBackend
ldap:
serverUri: ldap://domain.com
startTls: true
ignoreCertErrors: true
bindDn: ""
bindPassword: ""
# and ALL the other remoteAuth.ldap.* settings from values.yaml
```
> [!NOTE]
> In order to use anonymous LDAP binding, set `bindDn` and `bindPassword`
> to an empty string as in the example above.
### LDAP Certificate Verification
If you need to specify your own CA certificate, follow the instructions below.
#### Option 1. In your `values.yaml` file define the directory already containing your CA certificate
```yaml
ldap:
serverUri: ldap://domain.com
startTls: true
ignoreCertErrors: false
caCertDir: /etc/ssl/certs
```
#### Option 2. In your `values.yaml` file define your CA certificate content in `caCertData`
```yaml
ldap:
serverUri: ldap://domain.com
startTls: true
ignoreCertErrors: false
caCertData: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
```
================================================
FILE: charts/netbox/docs/extra.md
================================================
# Extra Configuration
## Overview
Any additional configuration setting can be passed in the chart
values to be loaded into NetBox's instance.
They may be provided as arbitrary configuration values set, or
you can load arbitrary `*.yaml` keys from ConfigMaps and Secrets.
```yaml
extraConfig:
- values:
EXTRA_SETTING_ONE: example
ANOTHER_SETTING: foobar
- configMap: # pod.spec.volumes.configMap
name: netbox-extra
items: []
optional: false
- secret: # same as pod.spec.volumes.secret
secretName: netbox-extra
items: []
optional: false
```
## NetBox Additional Configuration
For additional NetBox configuration setting, the recommended way is
to use the extra configuration value (`extraConfig`).
> [!note]
> In order to keep the chart's values reasonnable, only the
> [required](https://netboxlabs.com/docs/netbox/en/stable/configuration/required-parameters/)
> and critical configuration settings can be directly configured with a dedicated value field.
For example, the following snippet is configuring the value for
[`DEFAULT_DASHBOARD`](https://netboxlabs.com/docs/netbox/en/stable/configuration/default-values/#default_dashboard):
```yaml
extraConfig:
- values:
DEFAULT_DASHBOARD:
- widget: "extras.ObjectCountsWidget"
width: 4
```
## ConfigMaps and Secrets Use
Any ConfigMaps and Secrets can be leveraged to provide configuration parameters.
The resource must provide the data under a `*.yaml` file description.
```yaml
apiVersion: v1
kind: Secret
metadata:
name: netbox-okta-credentials
namespace: netbox
type: Opaque
stringData:
okta.yaml: |
SOCIAL_AUTH_OKTA_OPENIDCONNECT_KEY: ...
SOCIAL_AUTH_OKTA_OPENIDCONNECT_SECRET: ...
SOCIAL_AUTH_OKTA_OPENIDCONNECT_API_URL: ...
```
Then, it can be consumed using `extraConfig` using a the name as reference.
```yaml
extraConfig:
- secret:
secretName: netbox-okta-credentials
```
The variables will be retrieve by NetBox when loading.
In this example, the three variables (`SOCIAL_AUTH_OKTA_OPENIDCONNECT_*`)
will be available as global variables.
> [!tip]
> See more example of `extraConfig` within [Authentication Options](./auth.md) guide.
================================================
FILE: charts/netbox/docs/migrate.md
================================================
# Migration Guide
For major version updates (5.0.0, 6.0.0, etc.), see the release notes for detailed migration information.
## Back Up PostgreSQL
The first thing you should do is back up your PostgreSQL database.
This way you can always go back to your previous install version if anything goes wrong.
You can find your PostgreSQL pod by running `kubectl get pods -A | grep postgres` and then use `kubectl exec` to run `psql` or `pg_dump` from it.
## Upgrade PostgreSQL If Necessary
As of NetBox 3.6.x, NetBox requires PostgreSQL 12 or higher.
It is recommended that you upgrade to the latest supported PostgreSQL version.
If you are using the built-in PostgreSQL chart, you may need to update it separately, or update to the latest NetBox chart and dump your data back into it before NetBox will start.
## Upgrade NetBox
It is always recommended that you upgrade NetBox one major version at a time.
For example, if you are currently running NetBox 3.5.2 inside your chart, you would upgrade to the last 3.6.x version, then 3.7.x, and so on.
This ensures that migrations all run smoothly between versions.
## Check for Breaking Changes
Always look at the release notes for breaking changes.
There may be necessary changes to your `values.yaml` to ensure your configuration still works.
================================================
FILE: charts/netbox/docs/prod.md
================================================
# Production Considerations
## Database Recommendation
We recommend using separate external PostgreSQL and Key-Value instances. This
de-couples those services from the chart's bundled versions which may have
complex upgrade requirements. A clustered PostgreSQL server (e.g. using Zalando's
[Postgres Operator](https://github.com/zalando/postgres-operator)) and Redis
with Sentinel (e.g. using [Aaron Layfield](https://github.com/DandyDeveloper)'s
[redis-ha chart](https://github.com/DandyDeveloper/charts/tree/master/charts/redis-ha)).
## Storage Recommendation
Set `persistence.enabled` to `false` and use the S3 `storages`
for object storage. This works well with Minio or Ceph RGW as well as Amazon S3.
See [Persistent storage pitfalls](#persistent-storage-pitfalls), below.
Run multiple replicas of the NetBox web frontend to avoid interruptions during
upgrades or at other times when the pods need to be restarted. There's no need
to have multiple workers (`worker.replicaCount`) for better availability. Set
up `affinity.podAntiAffinity` to avoid multiple NetBox pods being colocated on
the same node, for example:
```yaml
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/instance: netbox
app.kubernetes.io/name: netbox
app.kubernetes.io/component: netbox
topologyKey: kubernetes.io/hostname
```
## Persistent Storage Pitfalls
Persistent storage for media is enabled by default, but unless you take special
care you will run into issues. The most common issue is that one of the NetBox
pods gets stuck in the `ContainerCreating` state. There are several ways around
this problem:
<!-- prettier-ignore-start -->
1. Use the recommended S3 `storageBackend` and **disable** persistent storage
by setting `persistence.enabled` to `false`. This can
be used with any S3-compatible storage provider including Amazon S3, Minio,
Ceph RGW, and many others. See further down for an example of this.
2. Use a `ReadWriteMany` volume that can be mounted by several pods across
nodes simultaneously.
3. Configure pod affinity settings to keep all the pods on the same node. This
allows a `ReadWriteOnce` volume to be mounted in several pods at the same
time.
4. Disable persistent storage of media altogether and just manage without. The
storage functionality is only needed to store uploaded image attachments.
<!-- prettier-ignore-end -->
To configure the pod affinity to allow using a `ReadWriteOnce` volume you can
use the following example configuration:
```yaml
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: netbox
topologyKey: kubernetes.io/hostname
housekeeping:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: netbox
topologyKey: kubernetes.io/hostname
worker:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: netbox
topologyKey: kubernetes.io/hostname
```
## Disruption Budgets
To minimize downtime during voluntary disruptions (node drains, upgrades, autoscaling evictions), the chart can create PodDisruptionBudgets (PDBs) for both the web and worker Deployments.
- Configure web PDB via `pdb.*` values.
- Configure worker PDB via `worker.pdb.*` values.
Examples:
```yaml
# Ensure at least one web pod stays available at all times
pdb:
enabled: true
minAvailable: 1
# Allow one worker to be evicted at a time
worker:
pdb:
enabled: true
maxUnavailable: 1
```
================================================
FILE: charts/netbox/files/configuration.py
================================================
"""
This file serves as a base configuration for Netbox
https://netboxlabs.com/docs/netbox/en/stable/configuration/
"""
import json
import os
import re
from pathlib import Path
import yaml
def _deep_merge(source, destination):
"""Inspired by https://stackoverflow.com/a/20666342"""
for key, value in source.items():
dst_value = destination.get(key)
if isinstance(value, dict) and isinstance(dst_value, dict):
_deep_merge(value, dst_value)
else:
destination[key] = value
return destination
def _load_yaml() -> None:
"""Load YAML from files"""
extra_config_base = Path("/run/config/extra")
config_files = [Path("/run/config/netbox/netbox.yaml")]
config_files.extend(sorted(extra_config_base.glob("*/*.yaml")))
for config_file in config_files:
with open(config_file, "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
_deep_merge(config, globals())
def _read_secret(secret_name: str, secret_key: str, default: str | None = None) -> str | None:
"""Read secret from file"""
try:
secret = open(
f"/run/secrets/{secret_name}/{secret_key}",
"r",
encoding="utf-8",
)
except EnvironmentError:
return default
with secret:
return secret.read().strip()
CORS_ORIGIN_REGEX_WHITELIST = []
DATABASES = {}
EMAIL = {}
REDIS = {}
_load_yaml()
provided_secret_name = os.getenv("SECRET_NAME", "netbox")
DATABASES["default"]["PASSWORD"] = _read_secret(provided_secret_name, "db_password")
EMAIL["PASSWORD"] = _read_secret(provided_secret_name, "email_password")
REDIS["tasks"]["PASSWORD"] = _read_secret(provided_secret_name, "tasks_password")
REDIS["caching"]["PASSWORD"] = _read_secret(provided_secret_name, "cache_password")
SECRET_KEY = _read_secret(provided_secret_name, "secret_key")
# Read API token peppers from secret (JSON with integer or string keys)
_peppers_raw = _read_secret(provided_secret_name, "api_token_peppers")
if _peppers_raw:
try:
API_TOKEN_PEPPERS = {int(k): v for k, v in json.loads(_peppers_raw).items()}
except (json.JSONDecodeError, ValueError, TypeError) as exc:
raise ValueError(
f"Invalid api_token_peppers secret: expected a JSON object mapping numeric "
f'string keys to string values, e.g. {{"1": "random-string..."}}. '
f"Keys are converted to integers at load time. Error: {exc}"
) from exc
# Post-process certain values
CORS_ORIGIN_REGEX_WHITELIST = [re.compile(r) for r in CORS_ORIGIN_REGEX_WHITELIST]
if "SENTINELS" in REDIS["tasks"]:
REDIS["tasks"]["SENTINELS"] = [tuple(x.split(r":")) for x in REDIS["tasks"]["SENTINELS"]]
if "SENTINELS" in REDIS["caching"]:
REDIS["caching"]["SENTINELS"] = [tuple(x.split(r":")) for x in REDIS["caching"]["SENTINELS"]]
if ALLOWED_HOSTS_INCLUDES_POD_ID:
ALLOWED_HOSTS.append(os.getenv("POD_IP"))
================================================
FILE: charts/netbox/files/ldap_config.py
================================================
"""
This file serves as a LDAP configuration for Netbox
https://netboxlabs.com/docs/netbox/en/stable/installation/6-ldap/#configuration
https://django-auth-ldap.readthedocs.io/en/latest/reference.html
"""
from functools import reduce
from importlib import import_module
from typing import Any
import ldap
import yaml
from django_auth_ldap.config import LDAPGroupQuery, LDAPSearch
def _load_yaml() -> None:
"""Load YAML from file"""
with open("/run/config/netbox/ldap.yaml", "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
globals().update(config)
def _read_secret(secret_name: str, secret_key: str, default: str | None = None) -> str | None:
"""Read secret from file"""
try:
secret = open(
f"/run/secrets/{secret_name}/{secret_key}",
"r",
encoding="utf-8",
)
except EnvironmentError:
return default
with secret:
return secret.readline().strip()
def _import_group_type(group_type_name: str) -> Any | None:
"""Import and return the group type based on name"""
mod = import_module("django_auth_ldap.config")
try:
return getattr(mod, group_type_name)()
except AttributeError:
return None
AUTH_LDAP_USER_SEARCH_FILTER = None
AUTH_LDAP_GROUP_SEARCH_FILTER = None
AUTH_LDAP_REQUIRE_GROUP = None
AUTH_LDAP_USER_FLAGS_BY_GROUP = {}
_load_yaml()
# The following may be needed if you are binding to Active Directory.
AUTH_LDAP_CONNECTION_OPTIONS = {ldap.OPT_REFERRALS: 0}
# Set the DN and password for the NetBox service account if needed.
AUTH_LDAP_BIND_PASSWORD = _read_secret("netbox", "ldap_bind_password")
# This search ought to return all groups to which the user belongs.
# django_auth_ldap uses this to determine group
# heirarchy.
AUTH_LDAP_USER_SEARCH = LDAPSearch(
AUTH_LDAP_USER_SEARCH_BASEDN,
ldap.SCOPE_SUBTREE,
AUTH_LDAP_USER_SEARCH_FILTER or f"({AUTH_LDAP_USER_SEARCH_ATTR}=%(user)s)",
)
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
AUTH_LDAP_GROUP_SEARCH_BASEDN,
ldap.SCOPE_SUBTREE,
AUTH_LDAP_GROUP_SEARCH_FILTER or f"(objectClass={AUTH_LDAP_GROUP_SEARCH_CLASS})",
)
AUTH_LDAP_GROUP_TYPE = _import_group_type(AUTH_LDAP_GROUP_TYPE)
# Define a group required to login.
if AUTH_LDAP_REQUIRE_GROUP_LIST:
AUTH_LDAP_REQUIRE_GROUP = reduce(
lambda query, group: query | LDAPGroupQuery(group),
AUTH_LDAP_REQUIRE_GROUP_LIST,
LDAPGroupQuery(""),
)
# Define special user types using groups. Exercise great caution when assigning superuser status.
if AUTH_LDAP_REQUIRE_GROUP is not None:
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
"is_active": AUTH_LDAP_REQUIRE_GROUP,
"is_staff": reduce(
lambda query, group: query | LDAPGroupQuery(group),
AUTH_LDAP_IS_ADMIN_LIST,
LDAPGroupQuery(""),
),
"is_superuser": reduce(
lambda query, group: query | LDAPGroupQuery(group),
AUTH_LDAP_IS_SUPERUSER_LIST,
LDAPGroupQuery(""),
),
}
================================================
FILE: charts/netbox/templates/NOTES.txt
================================================
CHART NAME: {{ .Chart.Name }}
CHART VERSION: {{ .Chart.Version }}
APP VERSION: {{ .Chart.AppVersion }}
** Please be patient while the chart is being deployed **
Netbox can be accessed through the following DNS name from within the cluster:
{{ include "common.names.fullname" . }}.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }} (port {{ .Values.service.port }})
To access Netbox site from outside the cluster follow the steps below.
{{- if .Values.ingress.enabled }}
You have configured NetBox to use an ingress controller, exposing the following URL(s):
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
- http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace {{ include "common.names.namespace" . | quote }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "common.names.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ include "common.names.namespace" . | quote }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
Get the application URL by running these commands:
export SERVICE_IP=$(kubectl get svc --namespace {{ include "common.names.namespace" . | quote }} {{ include "common.names.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ include "common.names.namespace" . | quote }} svc -w {{ include "common.names.fullname" . }}'
{{- else if contains "ClusterIP" .Values.service.type }}
Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace {{ include "common.names.namespace" . | quote }} -l "app.kubernetes.io/name={{ include "common.names.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:8080
{{- end }}
{{- include "netbox.validateValues" . }}
{{- include "common.warnings.rollingTag" .Values.image }}
{{- include "common.warnings.rollingTag" .Values.init.image }}
{{- include "common.warnings.resources" (dict "sections" (list "" "worker") "context" $) }}
================================================
FILE: charts/netbox/templates/_helpers.tpl
================================================
{{/* vim: set filetype=mustache: */}}
{{/*
Return the proper image name
*/}}
{{- define "netbox.image" -}}
{{- include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global "chart" .Chart) -}}
{{- end -}}
{{/*
Return the proper image name (for the init container image)
*/}}
{{- define "netbox.init.image" -}}
{{- include "common.images.image" (dict "imageRoot" .Values.init.image "global" .Values.global) -}}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "netbox.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "common.names.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Name of the key in Secret that contains the email password
*/}}
{{- define "netbox.email.secretKey" -}}
{{- if .Values.email.existingSecretName -}}
{{- .Values.email.existingSecretKey -}}
{{- else -}}
email_password
{{- end -}}
{{- end }}
{{/*
Name of the Secret that contains the PostgreSQL password
*/}}
{{- define "netbox.postgresql.secret" -}}
{{- if .Values.postgresql.enabled }}
{{- include "postgresql.v1.secretName" .Subcharts.postgresql -}}
{{- else }}
{{- include "common.secrets.name" (dict "existingSecret" .Values.externalDatabase.existingSecretName "defaultNameSuffix" "postgresql" "context" $) }}
{{- end }}
{{- end }}
{{/*
Name of the key in Secret that contains the PostgreSQL password
*/}}
{{- define "netbox.postgresql.secretKey" -}}
{{- if .Values.postgresql.enabled -}}
{{- include "postgresql.v1.userPasswordKey" .Subcharts.postgresql -}}
{{- else if .Values.externalDatabase.existingSecretName -}}
{{- .Values.externalDatabase.existingSecretKey -}}
{{- else -}}
db_password
{{- end -}}
{{- end }}
{{/*
Name of the Secret that contains the Valkey tasks password
*/}}
{{- define "netbox.tasksDatabase.secret" -}}
{{- if .Values.valkey.enabled }}
{{- include "valkey.secretName" .Subcharts.valkey -}}
{{- else }}
{{- include "common.secrets.name" (dict "existingSecret" .Values.tasksDatabase.existingSecretName "defaultNameSuffix" "kv" "context" $) }}
{{- end }}
{{- end }}
{{/*
Name of the key in Secret that contains the Valkey tasks password
*/}}
{{- define "netbox.tasksDatabase.secretKey" -}}
{{- if .Values.valkey.enabled -}}
{{- include "valkey.secretPasswordKey" .Subcharts.valkey -}}
{{- else if .Values.tasksDatabase.existingSecretName -}}
{{ .Values.tasksDatabase.existingSecretKey }}
{{- else -}}
tasks_password
{{- end -}}
{{- end }}
{{/*
Name of the Secret that contains the Valkey cache password
*/}}
{{- define "netbox.cachingDatabase.secret" -}}
{{- if .Values.valkey.enabled }}
{{- include "valkey.secretName" .Subcharts.valkey -}}
{{- else }}
{{- include "common.secrets.name" (dict "existingSecret" .Values.cachingDatabase.existingSecretName "defaultNameSuffix" "kv" "context" $) }}
{{- end }}
{{- end }}
{{/*
Name of the key in Secret that contains the Valkey cache password
*/}}
{{- define "netbox.cachingDatabase.secretKey" -}}
{{- if .Values.valkey.enabled -}}
{{- include "valkey.secretPasswordKey" .Subcharts.valkey -}}
{{- else if .Values.cachingDatabase.existingSecretName -}}
{{ .Values.cachingDatabase.existingSecretKey }}
{{- else -}}
cache_password
{{- end -}}
{{- end }}
{{/*
Valkey Sentinels that would result from setting .Values.valkey.enabled=true and .Values.valkey.sentinel.enabled=true
*/}}
{{- define "netbox.valkey.managedSentinels" -}}
{{- $sentinels := list }}
{{- $fullname := include "common.names.fullname" .Subcharts.valkey }}
{{- $headlessService := printf "%s-headless" (include "common.names.fullname" .Subcharts.valkey) }}
{{- $sentinelPort := toString .Values.valkey.sentinel.service.ports.sentinel }}
{{- range $i := until (int .Values.valkey.replica.replicaCount) }}
{{- $sentinels = append $sentinels (printf "%s-node-%s.%s:%s" $fullname (toString $i) $headlessService $sentinelPort) }}
{{- end }}
{{- toJson $sentinels }}
{{- end -}}
{{/*
Tasks Sentinel: use .Values.tasksDatabase.sentinels if defined. When using embedded Valkey Sentinel feature, fallback to generated sentinels
*/}}
{{- define "netbox.tasksDatabase.sentinels" -}}
{{- if .Values.tasksDatabase.sentinels }}
{{- toJson .Values.tasksDatabase.sentinels }}
{{- else if and .Values.valkey.enabled .Values.valkey.sentinel.enabled }}
{{- include "netbox.valkey.managedSentinels" . }}
{{- end }}
{{- end -}}
{{/*
Caching Sentinel: use .Values.cachingDatabase.sentinels if defined. When using embedded Valkey Sentinel feature, fallback to generated sentinels
*/}}
{{- define "netbox.cachingDatabase.sentinels" -}}
{{- if .Values.cachingDatabase.sentinels }}
{{- toJson .Values.cachingDatabase.sentinels }}
{{- else if and .Values.valkey.enabled .Values.valkey.sentinel.enabled }}
{{- include "netbox.valkey.managedSentinels" . }}
{{- end }}
{{- end -}}
{{/*
Volumes that need to be mounted for .Values.extraConfig entries
*/}}
{{- define "netbox.extraConfig.volumes" -}}
{{- range $index, $config := .Values.extraConfig }}
- name: {{ printf "extra-config-%d" $index | quote }}
{{- if $config.values }}
configMap:
name: {{ include "common.names.fullname" $ }}
items:
- key: {{ printf "extra-%d.yaml" $index | quote }}
path: {{ printf "extra-%d.yaml" $index | quote }}
{{- else if $config.configMap }}
configMap:
{{- include "common.tplvalues.render" (dict "value" $config.configMap "context" $) | nindent 4 }}
{{- else if $config.secret }}
secret:
{{- include "common.tplvalues.render" (dict "value" $config.secret "context" $) | nindent 4 }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Volume mounts for .Values.extraConfig entries
*/}}
{{- define "netbox.extraConfig.volumeMounts" -}}
{{- range $index, $config := .Values.extraConfig }}
- name: {{ printf "extra-config-%d" $index | quote }}
mountPath: /run/config/extra/{{ $index }}
readOnly: true
{{- end }}
{{- end }}
{{/*
Generate the api_token_peppers secret value.
Returns a base64-encoded, quoted JSON object.
Priority:
1. User-provided apiTokenPeppers from values.yaml (always wins for rotation)
2. Existing secret value (preserved across upgrades via lookup)
3. Auto-generated single pepper {"1": "<random 50 chars>"}
*/}}
{{- define "netbox.apiTokenPeppers.secret" -}}
{{- if not (empty .Values.apiTokenPeppers) -}}
{{- .Values.apiTokenPeppers | toJson | b64enc | quote }}
{{- else -}}
{{- $secretName := include "common.secrets.name" (dict "defaultNameSuffix" "config" "context" $) -}}
{{- $existingSecret := (lookup "v1" "Secret" (include "common.names.namespace" .) $secretName).data -}}
{{- if and $existingSecret (hasKey $existingSecret "api_token_peppers") -}}
{{- index $existingSecret "api_token_peppers" | quote }}
{{- else -}}
{{- $pepper := randAlphaNum 50 -}}
{{- dict "1" $pepper | toJson | b64enc | quote }}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Compile all warnings into a single message.
*/}}
{{- define "netbox.validateValues" -}}
{{- $messages := list -}}
{{- $messages := append $messages (include "netbox.validateValues.postgresql" .) -}}
{{- $messages := append $messages (include "netbox.validateValues.ldap" .) -}}
{{- $messages := without $messages "" -}}
{{- $message := join "\n" $messages -}}
{{- if $message -}}
{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}}
{{- end -}}
{{- end -}}
{{/*
Validate values of Netbox Chart - PostgreSQL
*/}}
{{- define "netbox.validateValues.postgresql" -}}
{{- if and (not .Values.postgresql.enabled) (or (empty .Values.externalDatabase.host) (empty .Values.externalDatabase.port) (empty .Values.externalDatabase.database)) -}}
netbox: postgresql
PostgreSQL installation has been disabled but without the required parameters
to use an external database. To use an external database, please ensure you provide
(at least) the following values:
externalDatabase.host=DB_SERVER_HOST
externalDatabase.database=DB_NAME
externalDatabase.port=DB_SERVER_PORT
{{- end -}}
{{- end -}}
{{/*
Validate values of Netbox Chart - LDAP
*/}}
{{- define "netbox.validateValues.ldap" -}}
{{- if and (has "netbox.authentication.LDAPBackend" .Values.remoteAuth.backends) (empty .Values.remoteAuth.ldap.serverUri) -}}
netbox: remoteAuth.ldap
When LDAP backend is activated, you must provide all the necessary parameters.
Review the values under `remoteAuth.ldap`.
{{- end -}}
{{- end -}}
================================================
FILE: charts/netbox/templates/configmap.yaml
================================================
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "common.names.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
data:
configuration.py: |-
{{ .Files.Get "files/configuration.py" | nindent 4 }}
netbox.yaml: |-
ALLOWED_HOSTS: {{ toJson .Values.allowedHosts }}
ALLOWED_HOSTS_INCLUDES_POD_ID: {{ .Values.allowedHostsIncludesPodIP }}
DATABASES:
default:
{{- if .Values.postgresql.enabled }}
HOST: {{ include "postgresql.v1.primary.fullname" .Subcharts.postgresql | quote }}
USER: {{ include "postgresql.v1.username" .Subcharts.postgresql | quote }}
NAME: {{ include "postgresql.v1.database" .Subcharts.postgresql | quote }}
PORT: {{ include "postgresql.v1.service.port" .Subcharts.postgresql | int }}
{{- else }}
HOST: {{ include "common.tplvalues.render" (dict "value" .Values.externalDatabase.host "context" $) | quote }}
USER: {{ include "common.tplvalues.render" (dict "value" .Values.externalDatabase.username "context" $) | quote }}
NAME: {{ include "common.tplvalues.render" (dict "value" .Values.externalDatabase.database "context" $) | quote }}
PORT: {{ include "common.tplvalues.render" (dict "value" .Values.externalDatabase.port "context" $) | int }}
{{- end }}
ENGINE: {{ .Values.externalDatabase.engine | quote }}
OPTIONS: {{- include "common.tplvalues.render" (dict "value" .Values.externalDatabase.options "context" $) | nindent 10 }}
CONN_MAX_AGE: {{ .Values.externalDatabase.connMaxAge | int }}
DISABLE_SERVER_SIDE_CURSORS: {{ toJson .Values.externalDatabase.disableServerSideCursors }}
{{- range $key, $db := .Values.additionalDatabases }}
{{ $key }}:
ENGINE: {{ $db.engine | quote }}
NAME: {{ $db.database | quote }}
USER: {{ $db.username | quote }}
HOST: {{ $db.host | quote }}
PORT: {{ $db.port | int }}
CONN_MAX_AGE: {{ $db.connMaxAge | int }}
OPTIONS: {{- include "common.tplvalues.render" (dict "value" $db.options "context" $) | nindent 10 }}
DISABLE_SERVER_SIDE_CURSORS: {{ toJson $db.disableServerSideCursors }}
{{- end }}
ADMINS: {{ toJson .Values.admins }}
ALLOW_TOKEN_RETRIEVAL: {{ toJson .Values.allowTokenRetrieval }}
AUTH_PASSWORD_VALIDATORS: {{ toJson .Values.authPasswordValidators }}
ALLOWED_URL_SCHEMES: {{ toJson .Values.allowedUrlSchemes }}
{{- range $k, $v := .Values.banner }}
BANNER_{{ upper $k }}: {{ $v | quote }}
{{- end }}
BASE_PATH: {{ .Values.basePath | quote }}
CHANGELOG_RETENTION: {{ int .Values.changelogRetention }}
CUSTOM_VALIDATORS: {{ toJson .Values.customValidators }}
DEFAULT_USER_PREFERENCES: {{ toJson .Values.defaultUserPreferences }}
CORS_ORIGIN_ALLOW_ALL: {{ toJson .Values.cors.originAllowAll }}
CORS_ORIGIN_WHITELIST: {{ toJson .Values.cors.originWhitelist }}
CORS_ORIGIN_REGEX_WHITELIST: {{ toJson .Values.cors.originRegexWhitelist }}
CSRF_TRUSTED_ORIGINS: {{ toJson .Values.csrf.trustedOrigins }}
DATA_UPLOAD_MAX_MEMORY_SIZE: {{ int .Values.dataUploadMaxMemorySize }}
DEBUG: {{ toJson .Values.debug }}
DEFAULT_LANGUAGE: {{ .Values.defaultLanguage | quote }}
EMAIL:
SERVER: {{ .Values.email.server | quote }}
PORT: {{ .Values.email.port | int }}
USERNAME: {{ .Values.email.username | quote }}
USE_SSL: {{ toJson .Values.email.useSSL }}
USE_TLS: {{ toJson .Values.email.useTLS }}
SSL_CERTFILE: {{ .Values.email.sslCertFile | quote }}
SSL_KEYFILE: {{ .Values.email.sslKeyFile | quote }}
TIMEOUT: {{ .Values.email.timeout | int }}
FROM_EMAIL: {{ toJson .Values.email.from }}
ENFORCE_GLOBAL_UNIQUE: {{ toJson .Values.enforceGlobalUnique }}
EXEMPT_VIEW_PERMISSIONS: {{ toJson .Values.exemptViewPermissions }}
FIELD_CHOICES: {{ toJson .Values.fieldChoices }}
FILE_UPLOAD_MAX_MEMORY_SIZE: {{ int .Values.fileUploadMaxMemorySize }}
GRAPHQL_ENABLED: {{ toJson .Values.graphQlEnabled }}
HTTP_PROXIES: {{ toJson .Values.httpProxies }}
INTERNAL_IPS: {{ toJson .Values.internalIPs }}
JOB_RETENTION: {{ int .Values.jobRetention }}
LOGGING: {{ toJson .Values.logging }}
LOGIN_PERSISTENCE: {{ toJson .Values.loginPersistence }}
LOGIN_REQUIRED: {{ toJson .Values.loginRequired }}
LOGIN_TIMEOUT: {{ int .Values.loginTimeout }}
LOGOUT_REDIRECT_URL: {{ .Values.logoutRedirectUrl | quote }}
{{- if ne nil .Values.maintenanceMode }}
MAINTENANCE_MODE: {{ toJson .Values.maintenanceMode }}
{{- end }}
MAPS_URL: {{ .Values.mapsUrl | quote }}
MAX_PAGE_SIZE: {{ int .Values.maxPageSize }}
MEDIA_ROOT: /opt/netbox/netbox/media
STORAGES: {{ toJson .Values.storages }}
METRICS_ENABLED: {{ toJson .Values.metrics.enabled }}
PAGINATE_COUNT: {{ int .Values.paginateCount }}
PLUGINS: {{ toJson .Values.plugins }}
PLUGINS_CONFIG: {{ toJson .Values.pluginsConfig }}
POWERFEED_DEFAULT_AMPERAGE: {{ int .Values.powerFeedDefaultAmperage }}
POWERFEED_DEFAULT_MAX_UTILIZATION: {{ int .Values.powerFeedMaxUtilisation }}
POWERFEED_DEFAULT_VOLTAGE: {{ int .Values.powerFeedDefaultVoltage }}
PREFER_IPV4: {{ toJson .Values.preferIPv4 }}
RACK_ELEVATION_DEFAULT_UNIT_HEIGHT: {{ int .Values.rackElevationDefaultUnitHeight }}
RACK_ELEVATION_DEFAULT_UNIT_WIDTH: {{ int .Values.rackElevationDefaultUnitWidth }}
REMOTE_AUTH_ENABLED: {{ toJson .Values.remoteAuth.enabled }}
REMOTE_AUTH_BACKEND: {{ toJson .Values.remoteAuth.backends }}
REMOTE_AUTH_HEADER: {{ .Values.remoteAuth.header | quote }}
REMOTE_AUTH_USER_FIRST_NAME: {{ .Values.remoteAuth.userFirstName | quote }}
REMOTE_AUTH_USER_LAST_NAME: {{ .Values.remoteAuth.userLastName | quote }}
REMOTE_AUTH_USER_EMAIL: {{ .Values.remoteAuth.userEmail | quote }}
REMOTE_AUTH_AUTO_CREATE_USER: {{ toJson .Values.remoteAuth.autoCreateUser }}
REMOTE_AUTH_AUTO_CREATE_GROUPS: {{ toJson .Values.remoteAuth.autoCreateGroups }}
REMOTE_AUTH_DEFAULT_GROUPS: {{ toJson .Values.remoteAuth.defaultGroups }}
REMOTE_AUTH_DEFAULT_PERMISSIONS: {{ toJson .Values.remoteAuth.defaultPermissions }}
REMOTE_AUTH_GROUP_SYNC_ENABLED: {{ toJson .Values.remoteAuth.groupSyncEnabled }}
REMOTE_AUTH_GROUP_HEADER: {{ .Values.remoteAuth.groupHeader | quote }}
REMOTE_AUTH_SUPERUSER_GROUPS: {{ toJson .Values.remoteAuth.superuserGroups }}
REMOTE_AUTH_SUPERUSERS: {{ toJson .Values.remoteAuth.superusers }}
REMOTE_AUTH_STAFF_GROUPS: {{ toJson .Values.remoteAuth.staffGroups }}
REMOTE_AUTH_STAFF_USERS: {{ toJson .Values.remoteAuth.staffUsers }}
REMOTE_AUTH_GROUP_SEPARATOR: {{ .Values.remoteAuth.groupSeparator | quote }}
RELEASE_CHECK_URL: {{ toJson .Values.releaseCheck.url }}
REDIS:
tasks:
{{- if (include "netbox.tasksDatabase.sentinels" .) }}
SENTINELS: {{ include "netbox.tasksDatabase.sentinels" . }}
SENTINEL_SERVICE: {{ ternary .Values.valkey.sentinel.primarySet .Values.tasksDatabase.sentinelService (empty .Values.tasksDatabase.sentinels) | quote }}
SENTINEL_TIMEOUT: {{ .Values.tasksDatabase.sentinelTimeout | int }}
{{- else if .Values.valkey.enabled }}
HOST: {{ printf "%s-primary" (include "common.names.fullname" .Subcharts.valkey) | quote }}
PORT: {{ .Values.valkey.primary.service.ports.valkey | int }}
{{- else }}
HOST: {{ .Values.tasksDatabase.host | quote }}
PORT: {{ .Values.tasksDatabase.port | int }}
{{- end }}
USERNAME: {{ .Values.tasksDatabase.username | quote }}
DATABASE: {{ int .Values.tasksDatabase.database }}
SSL: {{ toJson .Values.tasksDatabase.ssl }}
INSECURE_SKIP_TLS_VERIFY: {{ toJson .Values.tasksDatabase.insecureSkipTlsVerify }}
CA_CERT_PATH: {{ .Values.tasksDatabase.caCertPath | quote }}
caching:
{{- if (include "netbox.cachingDatabase.sentinels" .) }}
SENTINELS: {{ include "netbox.cachingDatabase.sentinels" . }}
SENTINEL_SERVICE: {{ ternary .Values.valkey.sentinel.primarySet .Values.cachingDatabase.sentinelService (empty .Values.cachingDatabase.sentinels) | quote }}
SENTINEL_TIMEOUT: {{ .Values.cachingDatabase.sentinelTimeout | int }}
{{- else if .Values.valkey.enabled }}
HOST: {{ printf "%s-primary" (include "common.names.fullname" .Subcharts.valkey) | quote }}
PORT: {{ .Values.valkey.primary.service.ports.valkey | int }}
{{- else }}
HOST: {{ .Values.cachingDatabase.host | quote }}
PORT: {{ .Values.cachingDatabase.port | int}}
{{- end }}
USERNAME: {{ .Values.cachingDatabase.username | quote }}
DATABASE: {{ int .Values.cachingDatabase.database }}
SSL: {{ toJson .Values.cachingDatabase.ssl }}
INSECURE_SKIP_TLS_VERIFY: {{ toJson .Values.cachingDatabase.insecureSkipTlsVerify }}
CA_CERT_PATH: {{ .Values.cachingDatabase.caCertPath | quote }}
REPORTS_ROOT: /opt/netbox/netbox/reports
RQ_DEFAULT_TIMEOUT: {{ .Values.rqDefaultTimeout | int }}
SCRIPTS_ROOT: /opt/netbox/netbox/scripts
CSRF_COOKIE_NAME: {{ .Values.csrf.cookieName | quote }}
SESSION_COOKIE_NAME: {{ .Values.sessionCookieName }}
ENABLE_LOCALIZATION: {{ toJson .Values.enableLocalization }}
TIME_ZONE: {{ .Values.timeZone | quote }}
DATE_FORMAT: {{ .Values.dateFormat | quote }}
SHORT_DATE_FORMAT: {{ .Values.shortDateFormat | quote }}
TIME_FORMAT: {{ .Values.timeFormat | quote }}
SHORT_TIME_FORMAT: {{ .Values.shortTimeFormat | quote }}
DATETIME_FORMAT: {{ .Values.dateTimeFormat | quote }}
SHORT_DATETIME_FORMAT: {{ .Values.shortDateTimeFormat | quote }}
{{- if has "netbox.authentication.LDAPBackend" .Values.remoteAuth.backends }}
ldap_config.py: |-
{{ .Files.Get "files/ldap_config.py" | nindent 4 }}
ldap.yaml: |-
AUTH_LDAP_SERVER_URI: {{ .Values.remoteAuth.ldap.serverUri | quote }}
AUTH_LDAP_BIND_DN: {{ .Values.remoteAuth.ldap.bindDn | quote }}
AUTH_LDAP_START_TLS: {{ toJson .Values.remoteAuth.ldap.startTls }}
LDAP_IGNORE_CERT_ERRORS: {{ toJson .Values.remoteAuth.ldap.ignoreCertErrors }}
{{- if .Values.remoteAuth.ldap.caCertDir }}
LDAP_CA_CERT_DIR: {{ .Values.remoteAuth.ldap.caCertDir | quote }}
{{- end }}
{{- if .Values.remoteAuth.ldap.caCertData }}
LDAP_CA_CERT_FILE: /etc/netbox/config/ldap/ldap_ca.crt
{{- end }}
AUTH_LDAP_USER_DN_TEMPLATE: {{ default nil .Values.remoteAuth.ldap.userDnTemplate }}
AUTH_LDAP_USER_SEARCH_BASEDN: {{ .Values.remoteAuth.ldap.userSearchBaseDn | quote }}
AUTH_LDAP_USER_SEARCH_ATTR: {{ .Values.remoteAuth.ldap.userSearchAttr | quote }}
AUTH_LDAP_GROUP_SEARCH_BASEDN: {{ .Values.remoteAuth.ldap.groupSearchBaseDn | quote }}
AUTH_LDAP_GROUP_SEARCH_CLASS: {{ .Values.remoteAuth.ldap.groupSearchClass | quote }}
AUTH_LDAP_GROUP_TYPE: {{ .Values.remoteAuth.ldap.groupType | quote }}
AUTH_LDAP_FIND_GROUP_PERMS: {{ toJson .Values.remoteAuth.ldap.findGroupPerms }}
AUTH_LDAP_MIRROR_GROUPS: {{ toJson .Values.remoteAuth.ldap.mirrorGroups }}
AUTH_LDAP_MIRROR_GROUPS_EXCEPT: {{ toJson .Values.remoteAuth.ldap.mirrorGroupsExcept }}
AUTH_LDAP_CACHE_TIMEOUT: {{ int .Values.remoteAuth.ldap.cacheTimeout }}
AUTH_LDAP_REQUIRE_GROUP_LIST: {{ toJson .Values.remoteAuth.ldap.requireGroupDn }}
AUTH_LDAP_IS_ADMIN_LIST: {{ toJson .Values.remoteAuth.ldap.isAdminDn }}
AUTH_LDAP_IS_SUPERUSER_LIST: {{ toJson .Values.remoteAuth.ldap.isSuperUserDn }}
# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP:
first_name: {{ .Values.remoteAuth.ldap.attrFirstName | quote }}
last_name: {{ .Values.remoteAuth.ldap.attrLastName | quote }}
email: {{ .Values.remoteAuth.ldap.attrMail | quote }}
{{- if .Values.remoteAuth.ldap.caCertData }}
ldap_ca.crt: {{- toYaml .Values.remoteAuth.ldap.caCertData | indent 4 }}
{{- end }}
{{- end }}
{{- range $index, $config := .Values.extraConfig }}
{{- if $config.values }}
{{ printf "extra-%d.yaml" $index }}: |-
{{- include "common.tplvalues.render" (dict "value" $config.values "context" $) | nindent 4 }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/cronjob.yaml
================================================
{{- if .Values.housekeeping.enabled -}}
apiVersion: batch/v1
kind: CronJob
metadata:
name: {{ printf "%s-housekeeping" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
app.kubernetes.io/component: housekeeping
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
concurrencyPolicy: {{ .Values.housekeeping.concurrencyPolicy }}
failedJobsHistoryLimit: {{ .Values.housekeeping.failedJobsHistoryLimit }}
schedule: {{ .Values.housekeeping.schedule | quote }}
successfulJobsHistoryLimit: {{ .Values.housekeeping.successfulJobsHistoryLimit }}
suspend: {{ .Values.housekeeping.suspend }}
{{- if .Values.housekeeping.timezone }}
timeZone: {{ .Values.housekeeping.timezone }}
{{- end }}
jobTemplate:
metadata:
labels:
{{- include "common.labels.standard" . | nindent 8 }}
spec:
template:
metadata:
{{- if .Values.housekeeping.podAnnotations }}
annotations:
{{- include "common.tplvalues.render" ( dict "value" .Values.housekeeping.podAnnotations "context" $ ) | nindent 12 }}
{{- end }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.housekeeping.podLabels "context" $ ) | nindent 12 }}
app.kubernetes.io/component: housekeeping
spec:
{{- include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" $) | nindent 10 }}
serviceAccountName: {{ include "netbox.serviceAccountName" . }}
automountServiceAccountToken: {{ .Values.housekeeping.automountServiceAccountToken }}
{{- if .Values.housekeeping.podSecurityContext.enabled }}
securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.housekeeping.podSecurityContext "context" $) | nindent 12 }}
{{- end }}
{{- if .Values.housekeeping.initContainers }}
initContainers: {{- include "common.tplvalues.render" (dict "value" .Values.housekeeping.initContainers "context" $) | trim | nindent 12 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}-housekeeping
{{- if .Values.housekeeping.securityContext.enabled }}
securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.housekeeping.securityContext "context" $) | nindent 14 }}
{{- end }}
image: {{ include "netbox.image" . | quote }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.housekeeping.command }}
command: {{- include "common.tplvalues.render" (dict "value" .Values.housekeeping.command "context" $) | nindent 14 }}
{{- end }}
{{- if .Values.housekeeping.args }}
args: {{- include "common.tplvalues.render" (dict "value" .Values.housekeeping.args "context" $) | nindent 14 }}
{{- end }}
{{- if .Values.housekeeping.extraEnvs }}
env: {{- include "common.tplvalues.render" (dict "value" .Values.housekeeping.extraEnvs "context" $) | nindent 14 }}
{{- end }}
{{- if or .Values.housekeeping.extraEnvVarsCM .Values.housekeeping.extraEnvVarsSecret }}
envFrom:
{{- if .Values.housekeeping.extraEnvVarsCM }}
- configMapRef:
name: {{ include "common.tplvalues.render" (dict "value" .Values.housekeeping.extraEnvVarsCM "context" $) }}
{{- end }}
{{- if .Values.housekeeping.extraEnvVarsSecret }}
- secretRef:
name: {{ include "common.tplvalues.render" (dict "value" .Values.housekeeping.extraEnvVarsSecret "context" $) }}
{{- end }}
{{- end }}
volumeMounts:
- name: config
mountPath: /etc/netbox/config/configuration.py
subPath: configuration.py
readOnly: true
{{- if has "netbox.authentication.LDAPBackend" .Values.remoteAuth.backends }}
- name: config
mountPath: /etc/netbox/config/ldap/ldap_config.py
subPath: ldap_config.py
readOnly: true
{{- if .Values.remoteAuth.ldap.caCertData }}
- name: config
mountPath: /etc/netbox/config/ldap/ldap_ca.crt
subPath: ldap_ca.crt
readOnly: true
{{- end }}
{{- end }}
- name: config
mountPath: /run/config/netbox
readOnly: true
- name: secrets
mountPath: /run/secrets/netbox
readOnly: true
{{- include "netbox.extraConfig.volumeMounts" . | nindent 12 }}
- name: netbox-tmp
mountPath: /tmp
- name: media
mountPath: /opt/netbox/netbox/media
subPath: {{ .Values.persistence.subPath | default "" | quote }}
readOnly: {{ .Values.housekeeping.readOnlyPersistence | default false }}
{{- if .Values.reportsPersistence.enabled }}
- name: reports
mountPath: /opt/netbox/netbox/reports
subPath: {{ .Values.reportsPersistence.subPath | default "" | quote }}
readOnly: {{ .Values.housekeeping.readOnlyPersistence | default false }}
{{- end }}
{{- if .Values.scriptsPersistence.enabled }}
- name: scripts
mountPath: /opt/netbox/netbox/scripts
subPath: {{ .Values.scriptsPersistence.subPath | default "" | quote }}
readOnly: {{ .Values.housekeeping.readOnlyPersistence | default false }}
{{- end }}
{{- if .Values.housekeeping.extraVolumeMounts }}
{{- include "common.tplvalues.render" (dict "value" .Values.housekeeping.extraVolumeMounts "context" $) | nindent 12 }}
{{- end }}
{{- if .Values.housekeeping.resources }}
resources: {{ toYaml .Values.housekeeping.resources | nindent 14 }}
{{- else if ne .Values.housekeeping.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.housekeeping.resourcesPreset) | nindent 14 }}
{{- end }}
{{- if .Values.housekeeping.sidecars }}
{{- include "common.tplvalues.render" (dict "value" .Values.housekeeping.sidecars "context" $) | nindent 10 }}
{{- end }}
volumes:
- name: config
configMap:
name: {{ include "common.names.fullname" . }}
- name: secrets
projected:
sources:
- secret:
name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "defaultNameSuffix" "config" "context" $) }}
items:
- key: secret_key
path: secret_key
{{- if has "netbox.authentication.LDAPBackend" .Values.remoteAuth.backends }}
- key: ldap_bind_password
path: ldap_bind_password
{{- end }}
- secret:
name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "defaultNameSuffix" "config" "context" $) }}
optional: true
items:
- key: api_token_peppers
path: api_token_peppers
- secret:
name: {{ include "common.secrets.name" (dict "existingSecret" (default .Values.existingSecret .Values.email.existingSecretName) "defaultNameSuffix" "config" "context" $) }}
items:
- key: {{ include "netbox.email.secretKey" . | quote }}
path: email_password
- secret:
name: {{ include "netbox.postgresql.secret" . | quote }}
items:
- key: {{ include "netbox.postgresql.secretKey" . | quote }}
path: db_password
- secret:
name: {{ include "netbox.tasksDatabase.secret" . | quote }}
items:
- key: {{ include "netbox.tasksDatabase.secretKey" . | quote }}
path: tasks_password
- secret:
name: {{ include "netbox.cachingDatabase.secret" . | quote }}
items:
- key: {{ include "netbox.cachingDatabase.secretKey" . | quote }}
path: cache_password
{{- include "netbox.extraConfig.volumes" . | nindent 10 }}
- name: netbox-tmp
emptyDir:
medium: Memory
- name: media
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim | default (printf "%s-media" (include "common.names.fullname" .)) }}
readOnly: {{ .Values.housekeeping.readOnlyPersistence | default false }}
{{- else }}
emptyDir: {}
{{- end }}
{{- if .Values.reportsPersistence.enabled }}
- name: reports
persistentVolumeClaim:
claimName: {{ .Values.reportsPersistence.existingClaim | default (printf "%s-reports" (include "common.names.fullname" .)) }}
readOnly: {{ .Values.housekeeping.readOnlyPersistence | default false }}
{{- end }}
{{- if .Values.scriptsPersistence.enabled }}
- name: scripts
persistentVolumeClaim:
claimName: {{ .Values.scriptsPersistence.existingClaim | default (printf "%s-scripts" (include "common.names.fullname" .)) }}
readOnly: {{ .Values.housekeeping.readOnlyPersistence | default false }}
{{- end }}
{{- if .Values.housekeeping.extraVolumes }}
{{- include "common.tplvalues.render" (dict "value" .Values.housekeeping.extraVolumes "context" $) | nindent 10 }}
{{- end }}
{{- if .Values.housekeeping.nodeSelector }}
nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.housekeeping.nodeSelector "context" $) | nindent 12 }}
{{- end }}
{{- if .Values.housekeeping.affinity }}
affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.housekeeping.affinity "context" $) | nindent 12 }}
{{- end }}
{{- if .Values.housekeeping.tolerations }}
tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.housekeeping.tolerations "context" .) | nindent 12 }}
{{- end }}
restartPolicy: {{ .Values.housekeeping.restartPolicy }}
{{- end -}}
================================================
FILE: charts/netbox/templates/deployment.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "common.names.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
app.kubernetes.io/component: netbox
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels: {{- include "common.labels.matchLabels" (dict "customLabels" .Values.podLabels "context" $) | nindent 6 }}
app.kubernetes.io/component: netbox
{{- if .Values.updateStrategy }}
strategy: {{- include "common.tplvalues.render" (dict "value" .Values.updateStrategy "context" $) | nindent 4 }}
{{- end }}
template:
metadata:
annotations:
{{- if .Values.podAnnotations }}
{{- include "common.tplvalues.render" ( dict "value" .Values.podAnnotations "context" $ ) | nindent 8 }}
{{- end }}
checksum/config: {{ include "common.utils.checksumTemplate" (dict "path" "/configmap.yaml" "context" $) }}
{{- if (not .Values.existingSecret) }}
checksum/secret: {{ include "common.utils.checksumTemplate" (dict "path" "/secret.yaml" "context" $) }}
{{- end }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.podLabels "context" $ ) | nindent 8 }}
app.kubernetes.io/component: netbox
spec:
{{- include "common.images.renderPullSecrets" (dict "images" (list .Values.image) "context" $) | nindent 6 }}
serviceAccountName: {{ include "netbox.serviceAccountName" . }}
automountServiceAccountToken: {{ .Values.automountServiceAccountToken }}
{{- if .Values.podSecurityContext.enabled }}
securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.podSecurityContext "context" $) | nindent 8 }}
{{- end }}
initContainers:
- name: init-dirs
image: {{ include "netbox.init.image" . | quote }}
imagePullPolicy: {{ .Values.init.image.pullPolicy | quote }}
command: [/bin/sh, -c, mkdir -p /opt/unit/state /opt/unit/tmp]
{{- if .Values.init.resources }}
resources: {{- toYaml .Values.init.resources | nindent 11 }}
{{- else if ne .Values.init.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.init.resourcesPreset) | nindent 10 }}
{{- end }}
{{- if .Values.init.securityContext.enabled }}
securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.init.securityContext "context" $) | nindent 10 }}
{{- end }}
volumeMounts:
- name: optunit
mountPath: /opt/unit
{{- if .Values.initContainers }}
{{- include "common.tplvalues.render" (dict "value" .Values.initContainers "context" $) | trim | nindent 6 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{- if .Values.securityContext.enabled }}
securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.securityContext "context" $) | nindent 10 }}
{{- end }}
image: {{ include "netbox.image" . | quote }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.command }}
command: {{- include "common.tplvalues.render" (dict "value" .Values.command "context" $) | nindent 10 }}
{{- end }}
{{- if .Values.args }}
args: {{- include "common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 10 }}
{{- end }}
env:
- name: SUPERUSER_NAME
valueFrom:
secretKeyRef:
name: {{ include "common.secrets.name" (dict "existingSecret" .Values.superuser.existingSecret "defaultNameSuffix" "superuser" "context" $) }}
key: username
- name: SUPERUSER_EMAIL
valueFrom:
secretKeyRef:
name: {{ include "common.secrets.name" (dict "existingSecret" .Values.superuser.existingSecret "defaultNameSuffix" "superuser" "context" $) }}
key: email
{{- if and .Values.metrics.enabled .Values.metrics.granian.enabled }}
- name: GRANIAN_METRICS_ENABLED
value: {{ .Values.metrics.granian.enabled | quote }}
{{- if and .Values.metrics.granian.serviceMonitor.enabled .Values.metrics.granian.serviceMonitor.interval }}
- name: GRANIAN_METRICS_SCRAPE_INTERVAL
value: {{ .Values.metrics.granian.serviceMonitor.interval | quote }}
{{- end }}
{{- end }}
{{- if .Values.dbWaitDebug }}
- name: DB_WAIT_DEBUG
value: "1"
{{- end }}
{{- if .Values.allowedHostsIncludesPodIP }}
- name: POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
{{- end }}
{{- if .Values.extraEnvs }}
{{- include "common.tplvalues.render" (dict "value" .Values.extraEnvs "context" $) | nindent 8 }}
{{- end }}
{{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }}
envFrom:
{{- if .Values.extraEnvVarsCM }}
- configMapRef:
name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsCM "context" $) }}
{{- end }}
{{- if .Values.extraEnvVarsSecret }}
- secretRef:
name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }}
{{- end }}
{{- end }}
ports:
- name: http
containerPort: 8080
protocol: TCP
{{- if .Values.metrics.granian.serviceMonitor.enabled}}
- name: granian-metrics
containerPort: 9090
protocol: TCP
{{- end }}
{{- if .Values.customLivenessProbe }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 10 }}
{{- else if .Values.livenessProbe.enabled }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.livenessProbe "enabled") "context" $) | nindent 10 }}
tcpSocket:
port: http
{{- end }}
{{- if .Values.customReadinessProbe }}
readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 10 }}
{{- else if .Values.readinessProbe.enabled }}
readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.readinessProbe "enabled") "context" $) | nindent 10 }}
httpGet:
path: /{{ .Values.basePath }}login/
port: http
{{- if (not (eq (index .Values.allowedHosts 0) "*")) }}
httpHeaders:
- name: Host
value: {{ (index .Values.allowedHosts 0) | quote }}
{{- end }}
{{- end }}
{{- if .Values.customStartupProbe }}
startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customStartupProbe "context" $) | nindent 10 }}
{{- else if .Values.startupProbe.enabled }}
startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.startupProbe "enabled") "context" $) | nindent 10 }}
httpGet:
path: /{{ .Values.basePath }}login/
port: http
{{- if (not (eq (index .Values.allowedHosts 0) "*")) }}
httpHeaders:
- name: Host
value: {{ (index .Values.allowedHosts 0) | quote }}
{{- end }}
{{- end }}
{{- if .Values.lifecycleHooks }}
lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 10 }}
{{- end }}
volumeMounts:
- name: config
mountPath: /etc/netbox/config/configuration.py
subPath: configuration.py
readOnly: true
{{- if has "netbox.authentication.LDAPBackend" .Values.remoteAuth.backends }}
- name: config
mountPath: /etc/netbox/config/ldap/ldap_config.py
subPath: ldap_config.py
readOnly: true
{{- if .Values.remoteAuth.ldap.caCertData }}
- name: config
mountPath: /etc/netbox/config/ldap/ldap_ca.crt
subPath: ldap_ca.crt
readOnly: true
{{- end }}
{{- end }}
- name: config
mountPath: /run/config/netbox
readOnly: true
- name: secrets
mountPath: /run/secrets/netbox
readOnly: true
{{- include "netbox.extraConfig.volumeMounts" . | nindent 8 }}
- name: netbox-tmp
mountPath: /tmp
- name: media
mountPath: /opt/netbox/netbox/media
subPath: {{ .Values.persistence.subPath | default "" | quote }}
{{- if .Values.reportsPersistence.enabled }}
- name: reports
mountPath: /opt/netbox/netbox/reports
subPath: {{ .Values.reportsPersistence.subPath | default "" | quote }}
{{- end }}
{{- if .Values.scriptsPersistence.enabled }}
- name: scripts
mountPath: /opt/netbox/netbox/scripts
subPath: {{ .Values.scriptsPersistence.subPath | default "" | quote }}
{{- end }}
- name: optunit
mountPath: /opt/unit
- name: secrets
mountPath: /run/secrets/superuser_password
subPath: superuser_password
readOnly: true
- name: secrets
mountPath: /run/secrets/superuser_api_token
subPath: superuser_api_token
readOnly: true
{{- if .Values.extraVolumeMounts }}
{{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 8 }}
{{- end }}
{{- if .Values.resources }}
resources: {{- toYaml .Values.resources | nindent 10 }}
{{- else if ne .Values.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.resourcesPreset) | nindent 10 }}
{{- end }}
{{- if .Values.sidecars }}
{{- include "common.tplvalues.render" (dict "value" .Values.sidecars "context" $) | nindent 6 }}
{{- end }}
volumes:
- name: config
configMap:
name: {{ include "common.names.fullname" . }}
- name: secrets
projected:
sources:
- secret:
name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "defaultNameSuffix" "config" "context" $) }}
items:
- key: secret_key
path: secret_key
{{- if has "netbox.authentication.LDAPBackend" .Values.remoteAuth.backends }}
- key: ldap_bind_password
path: ldap_bind_password
{{- end }}
- secret:
name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "defaultNameSuffix" "config" "context" $) }}
optional: true
items:
- key: api_token_peppers
path: api_token_peppers
- secret:
name: {{ include "common.secrets.name" (dict "existingSecret" (default .Values.existingSecret .Values.email.existingSecretName) "defaultNameSuffix" "config" "context" $) }}
items:
- key: {{ include "netbox.email.secretKey" . | quote }}
path: email_password
- secret:
name: {{ include "common.secrets.name" (dict "existingSecret" .Values.superuser.existingSecret "defaultNameSuffix" "superuser" "context" $) }}
items:
- key: password
path: superuser_password
- key: api_token
path: superuser_api_token
- secret:
name: {{ include "netbox.postgresql.secret" . | quote }}
items:
- key: {{ include "netbox.postgresql.secretKey" . | quote }}
path: db_password
- secret:
name: {{ include "netbox.tasksDatabase.secret" . | quote }}
items:
- key: {{ include "netbox.tasksDatabase.secretKey" . | quote }}
path: tasks_password
- secret:
name: {{ include "netbox.cachingDatabase.secret" . | quote }}
items:
- key: {{ include "netbox.cachingDatabase.secretKey" . | quote }}
path: cache_password
{{- include "netbox.extraConfig.volumes" . | nindent 6 }}
- name: netbox-tmp
emptyDir:
medium: Memory
- name: optunit
emptyDir:
medium: Memory
- name: media
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim | default (printf "%s-media" (include "common.names.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- if .Values.reportsPersistence.enabled }}
- name: reports
persistentVolumeClaim:
claimName: {{ .Values.reportsPersistence.existingClaim | default (printf "%s-reports" (include "common.names.fullname" .)) }}
{{- end }}
{{- if .Values.scriptsPersistence.enabled }}
- name: scripts
persistentVolumeClaim:
claimName: {{ .Values.scriptsPersistence.existingClaim | default (printf "%s-scripts" (include "common.names.fullname" .)) }}
{{- end }}
{{- if .Values.extraVolumes }}
{{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 6 }}
{{- end }}
{{- if .Values.nodeSelector }}
nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.nodeSelector "context" $) | nindent 8 }}
{{- end }}
{{- if .Values.affinity }}
affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.affinity "context" $) | nindent 8 }}
{{- end }}
{{- if .Values.tolerations }}
tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" .) | nindent 8 }}
{{- end }}
{{- if .Values.hostAliases }}
hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }}
{{- end }}
{{- if .Values.priorityClassName }}
priorityClassName: {{ .Values.priorityClassName | quote }}
{{- end }}
{{- if .Values.schedulerName }}
schedulerName: {{ .Values.schedulerName | quote }}
{{- end }}
{{- if .Values.topologySpreadConstraints }}
topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.topologySpreadConstraints "context" .) | nindent 8 }}
{{- end }}
{{- if .Values.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
{{- end }}
================================================
FILE: charts/netbox/templates/extra-list.yaml
================================================
{{ range .Values.extraDeploy }}
---
{{ include "common.tplvalues.render" (dict "value" . "context" $) }}
{{ end }}
================================================
FILE: charts/netbox/templates/granian-servicemonitor.yaml
================================================
{{- if and .Values.metrics.granian.enabled .Values.metrics.granian.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ printf "%s-granian" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }}
namespace: {{ include "common.names.namespace" . | quote }}
{{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.metrics.granian.serviceMonitor.additionalLabels .Values.commonLabels ) "context" . ) }}
labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
jobLabel: {{ include "common.names.fullname" . }}
namespaceSelector:
matchNames:
- {{ include "common.names.namespace" . | quote }}
selector:
matchLabels:
{{- include "common.labels.matchLabels" . | nindent 6 }}
{{- if .Values.metrics.granian.serviceMonitor.selector }}
{{- include "common.tplvalues.render" (dict "value" .Values.metrics.granian.serviceMonitor.selector "context" $) | nindent 6 }}
{{- end }}
endpoints:
- port: granian-metrics
path: "/metrics"
{{- if .Values.metrics.granian.serviceMonitor.interval }}
interval: {{ .Values.metrics.granian.serviceMonitor.interval }}
{{- end }}
{{- if .Values.metrics.granian.serviceMonitor.scrapeTimeout }}
scrapeTimeout: {{ .Values.metrics.granian.serviceMonitor.scrapeTimeout }}
{{- end }}
{{- if .Values.metrics.granian.serviceMonitor.honorLabels }}
honorLabels: {{ .Values.metrics.granian.serviceMonitor.honorLabels }}
{{- end }}
{{- if .Values.metrics.granian.serviceMonitor.metricRelabelings }}
metricRelabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.granian.serviceMonitor.metricRelabelings "context" $) | nindent 6 }}
{{- end }}
{{- if .Values.metrics.granian.serviceMonitor.relabelings }}
relabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.granian.serviceMonitor.relabelings "context" $) | nindent 6 }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/hpa.yaml
================================================
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "common.names.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
app.kubernetes.io/component: netbox
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "common.names.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
{{- if .Values.autoscaling.behavior }}
behavior:
{{- if .Values.autoscaling.behavior.scaleUp }}
scaleUp:
{{- if .Values.autoscaling.behavior.scaleUp.stabilizationWindowSeconds }}
stabilizationWindowSeconds: {{ .Values.autoscaling.behavior.scaleUp.stabilizationWindowSeconds }}
{{- end }}
{{- if .Values.autoscaling.behavior.scaleUp.selectPolicy }}
selectPolicy: {{ .Values.autoscaling.behavior.scaleUp.selectPolicy | quote }}
{{- end }}
{{- if .Values.autoscaling.behavior.scaleUp.policies }}
policies:
{{- range .Values.autoscaling.behavior.scaleUp.policies }}
- type: {{ .type | quote }}
value: {{ .value }}
periodSeconds: {{ .periodSeconds }}
{{- end }}
{{- end }}
{{- end }}
{{- if .Values.autoscaling.behavior.scaleDown }}
scaleDown:
{{- if .Values.autoscaling.behavior.scaleDown.stabilizationWindowSeconds }}
stabilizationWindowSeconds: {{ .Values.autoscaling.behavior.scaleDown.stabilizationWindowSeconds }}
{{- end }}
{{- if .Values.autoscaling.behavior.scaleDown.selectPolicy }}
selectPolicy: {{ .Values.autoscaling.behavior.scaleDown.selectPolicy | quote }}
{{- end }}
{{- if .Values.autoscaling.behavior.scaleDown.policies }}
policies:
{{- range .Values.autoscaling.behavior.scaleDown.policies }}
- type: {{ .type | quote }}
value: {{ .value }}
periodSeconds: {{ .periodSeconds }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/httproute.yaml
================================================
{{- if .Values.httpRoute.enabled -}}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ include "common.names.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if or .Values.httpRoute.annotations .Values.commonAnnotations }}
{{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.httpRoute.annotations .Values.commonAnnotations) "context" .) }}
annotations:
{{- include "common.tplvalues.render" (dict "value" $annotations "context" $) | nindent 4 }}
{{- end }}
spec:
{{- with .Values.httpRoute.parentRefs }}
parentRefs:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httpRoute.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
- matches:
- path:
type: PathPrefix
value: /
{{- with .Values.httpRoute.filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
backendRefs:
- name: {{ include "common.names.fullname" . }}
port: {{ .Values.service.port }}
{{- end }}
================================================
FILE: charts/netbox/templates/ingress.yaml
================================================
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "common.names.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if or .Values.ingress.annotations .Values.commonAnnotations }}
{{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.ingress.annotations .Values.commonAnnotations ) "context" . ) }}
annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className | quote }}
{{- end }}
{{- with .Values.ingress.tls }}
tls:
{{- range . }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
{{- if kindIs "string" . }}
- path: {{ . }}
pathType: Prefix
backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 10 }}
{{- else }}
{{- (list .) | toYaml | nindent 6 }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/pdb.yaml
================================================
{{- if and .Values.pdb.enabled (or .Values.pdb.minAvailable .Values.pdb.maxUnavailable) }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "common.names.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
app.kubernetes.io/component: netbox
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels: {{- include "common.labels.matchLabels" (dict "customLabels" .Values.podLabels "context" $) | nindent 6 }}
app.kubernetes.io/component: netbox
{{- if .Values.pdb.minAvailable }}
minAvailable: {{ .Values.pdb.minAvailable }}
{{- end }}
{{- if .Values.pdb.maxUnavailable }}
maxUnavailable: {{ .Values.pdb.maxUnavailable }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/pvc.yaml
================================================
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ printf "%s-media" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if or .Values.persistence.annotations .Values.commonAnnotations }}
{{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.persistence.annotations .Values.commonAnnotations ) "context" . ) }}
annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- if .Values.persistence.selector }}
selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 4 }}
{{- end }}
{{- include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) | nindent 2 }}
{{- end }}
{{- if and .Values.reportsPersistence.enabled (not .Values.reportsPersistence.existingClaim) }}
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ printf "%s-reports" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if or .Values.reportsPersistence.annotations .Values.commonAnnotations }}
{{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.reportsPersistence.annotations .Values.commonAnnotations ) "context" . ) }}
annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.reportsPersistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.reportsPersistence.size | quote }}
{{- if .Values.reportsPersistence.selector }}
selector: {{- include "common.tplvalues.render" (dict "value" .Values.reportsPersistence.selector "context" $) | nindent 4 }}
{{- end }}
{{- include "common.storage.class" (dict "persistence" .Values.reportsPersistence "global" .Values.global) | nindent 2 }}
{{- end }}
{{- if and .Values.scriptsPersistence.enabled (not .Values.scriptsPersistence.existingClaim) }}
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ printf "%s-scripts" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if or .Values.scriptsPersistence.annotations .Values.commonAnnotations }}
{{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.scriptsPersistence.annotations .Values.commonAnnotations ) "context" . ) }}
annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.scriptsPersistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.scriptsPersistence.size | quote }}
{{- if .Values.scriptsPersistence.selector }}
selector: {{- include "common.tplvalues.render" (dict "value" .Values.scriptsPersistence.selector "context" $) | nindent 4 }}
{{- end }}
{{- include "common.storage.class" (dict "persistence" .Values.scriptsPersistence "global" .Values.global) | nindent 2 }}
{{- end }}
================================================
FILE: charts/netbox/templates/role.yaml
================================================
{{- if .Values.rbac.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "common.names.fullname" . }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
namespace: {{ include "common.names.namespace" . | quote }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
rules:
{{- if and .Values.worker.enabled .Values.worker.waitForBackend.enabled }}
- apiGroups:
- apps
resources:
- statefulsets
- deployments
- replicasets
verbs:
- get
- list
- watch
{{- end }}
{{- if .Values.rbac.rules }}
{{- include "common.tplvalues.render" ( dict "value" .Values.rbac.rules "context" $ ) | nindent 2 }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/rolebinding.yaml
================================================
{{- if .Values.rbac.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "common.names.fullname" . }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
namespace: {{ include "common.names.namespace" . | quote }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
roleRef:
kind: Role
name: {{ include "common.names.fullname" . }}
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: {{ include "netbox.serviceAccountName" . }}
namespace: {{ include "common.names.namespace" . | quote }}
{{- end }}
================================================
FILE: charts/netbox/templates/secret.yaml
================================================
{{- if not .Values.existingSecret }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "common.secrets.name" (dict "defaultNameSuffix" "config" "context" $) }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
type: Opaque
data:
{{- if not .Values.email.existingSecretName }}
email_password: {{ .Values.email.password | b64enc | quote }}
{{- end }}
secret_key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.secrets.name" (dict "defaultNameSuffix" "config" "context" $)) "key" "secret_key" "providedValues" (list "secretKey") "length" 60 "strong" true "failOnNew" false "context" $) }}
api_token_peppers: {{ include "netbox.apiTokenPeppers.secret" . }}
{{- if has "netbox.authentication.LDAPBackend" .Values.remoteAuth.backends }}
ldap_bind_password: {{ .Values.remoteAuth.ldap.bindPassword | b64enc | quote }}
{{- end }}
{{- end }}
{{- if not .Values.superuser.existingSecret }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "common.secrets.name" (dict "defaultNameSuffix" "superuser" "context" $) }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
type: kubernetes.io/basic-auth
data:
username: {{ .Values.superuser.name | default "admin" | b64enc | quote }}
password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.secrets.name" (dict "defaultNameSuffix" "superuser" "context" $)) "key" "password" "providedValues" (list "superuser.password") "context" $) }}
email: {{ .Values.superuser.email | b64enc | quote }}
api_token: {{ .Values.superuser.apiToken | default uuidv4 | b64enc | quote }}
{{- end }}
{{- if not (or .Values.postgresql.enabled .Values.externalDatabase.existingSecretName) }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "common.secrets.name" (dict "defaultNameSuffix" "postgresql" "context" $) }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
type: Opaque
data:
db_password: {{ .Values.externalDatabase.password | b64enc | quote }}
{{- end }}
{{- if not (or .Values.valkey.enabled (and .Values.tasksDatabase.existingSecretName .Values.cachingDatabase.existingSecretName)) }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "common.secrets.name" (dict "defaultNameSuffix" "kv" "context" $) }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
type: Opaque
data:
{{- if not .Values.tasksDatabase.existingSecretName }}
tasks_password: {{ .Values.tasksDatabase.password | b64enc | quote }}
{{- end }}
{{- if not .Values.cachingDatabase.existingSecretName }}
cache_password: {{ .Values.cachingDatabase.password | b64enc | quote }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/service.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: {{ include "common.names.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if or .Values.service.annotations .Values.commonAnnotations }}
{{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.service.annotations .Values.commonAnnotations ) "context" . ) }}
annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
{{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePort)) }}
nodePort: {{ .Values.service.nodePort }}
{{- else if eq .Values.service.type "ClusterIP" }}
nodePort: null
{{- end }}
{{- if and .Values.metrics.enabled .Values.metrics.granian.enabled }}
- port: 9090
targetPort: granian-metrics
protocol: TCP
name: granian-metrics
{{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePort)) }}
nodePort: {{ .Values.service.nodePort }}
{{- else if eq .Values.service.type "ClusterIP" }}
nodePort: null
{{- end }}
{{- end }}
selector:
{{- include "common.labels.matchLabels" . | nindent 4 }}
app.kubernetes.io/component: netbox
{{- if and .Values.service.clusterIP (eq .Values.service.type "ClusterIP") }}
clusterIP: {{ .Values.service.clusterIP }}
{{- end }}
{{- if and .Values.service.clusterIPs (eq .Values.service.type "ClusterIP") }}
clusterIPs: {{- include "common.tplvalues.render" (dict "value" .Values.service.clusterIPs "context" $) | nindent 4 }}
{{- end }}
{{- if .Values.service.externalIPs }}
clusterIPs: {{- include "common.tplvalues.render" (dict "value" .Values.service.externalIPs "context" $) | nindent 4 }}
{{- end }}
{{- if .Values.service.sessionAffinity }}
sessionAffinity: {{ .Values.service.sessionAffinity }}
{{- end }}
{{- if .Values.service.sessionAffinityConfig }}
sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.service.sessionAffinityConfig "context" $) | nindent 4 }}
{{- end }}
{{- if .Values.service.ipFamilyPolicy }}
ipFamilyPolicy: {{ .Values.service.ipFamilyPolicy | quote }}
{{- end }}
{{- if or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort") }}
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }}
{{- end }}
{{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerSourceRanges)) }}
loadBalancerSourceRanges: {{ .Values.service.loadBalancerSourceRanges }}
{{- end }}
{{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP)) }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }}
{{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerClass)) }}
loadBalancerClass: {{ .Values.service.loadBalancerClass | quote }}
{{- end }}
================================================
FILE: charts/netbox/templates/serviceaccount.yaml
================================================
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
metadata:
name: {{ include "netbox.serviceAccountName" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- if or .Values.commonAnnotations .Values.serviceAccount.annotations }}
{{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.serviceAccount.annotations .Values.commonAnnotations ) "context" . ) }}
annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/servicemonitor.yaml
================================================
{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "common.names.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
{{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.metrics.serviceMonitor.additionalLabels .Values.commonLabels ) "context" . ) }}
labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
jobLabel: {{ include "common.names.fullname" . }}
namespaceSelector:
matchNames:
- {{ include "common.names.namespace" . | quote }}
selector:
matchLabels:
{{- include "common.labels.matchLabels" . | nindent 6 }}
{{- if .Values.metrics.serviceMonitor.selector }}
{{- include "common.tplvalues.render" (dict "value" .Values.metrics.serviceMonitor.selector "context" $) | nindent 6 }}
{{- end }}
endpoints:
- port: http
path: "/metrics"
{{- if .Values.metrics.serviceMonitor.interval }}
interval: {{ .Values.metrics.serviceMonitor.interval }}
{{- end }}
{{- if .Values.metrics.serviceMonitor.scrapeTimeout }}
scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }}
{{- end }}
{{- if .Values.metrics.serviceMonitor.honorLabels }}
honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }}
{{- end }}
{{- if .Values.metrics.serviceMonitor.metricRelabelings }}
metricRelabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.metricRelabelings "context" $) | nindent 6 }}
{{- end }}
{{- if .Values.metrics.serviceMonitor.relabelings }}
relabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.relabelings "context" $) | nindent 6 }}
{{- end }}
{{- end }}
================================================
FILE: charts/netbox/templates/tests/test-connection.yaml
================================================
apiVersion: v1
kind: Pod
metadata:
name: {{ printf "%s-test-connection" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }}
labels:
{{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
annotations:
"helm.sh/hook": test
{{- if .Values.commonAnnotations }}
{{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
containers:
- name: wget
image: "{{ .Values.test.image.repository }}:{{ .Values.test.image.tag }}"
imagePullPolicy: {{ .Values.test.image.pullPolicy }}
command: ['wget']
args: ['{{ include "common.names.fullname" . }}:{{ .Values.service.port }}']
{{- if .Values.test.resources }}
resources: {{ toYaml .Values.test.resources | nindent 6 }}
{{- else if ne .Values.test.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.test.resourcesPreset) | nindent 6 }}
{{- end }}
{{- if .Values.test.securityContext.enabled }}
securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.test.securityContext "context" $) | nindent 6 }}
{{- end }}
restartPolicy: Never
================================================
FILE: charts/netbox/templates/worker/deployment.yaml
================================================
{{- if .Values.worker.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ printf "%s-worker" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
app.kubernetes.io/component: worker
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
{{- if not .Values.worker.autoscaling.enabled }}
replicas: {{ .Values.worker.replicaCount }}
{{- end }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels: {{- include "common.labels.matchLabels" (dict "customLabels" .Values.worker.podLabels "context" $) | nindent 6 }}
app.kubernetes.io/component: worker
{{- if .Values.worker.updateStrategy }}
strategy: {{- include "common.tplvalues.render" (dict "value" .Values.worker.updateStrategy "context" $) | nindent 4 }}
{{- end }}
template:
metadata:
annotations:
{{- if .Values.worker.podAnnotations }}
{{- include "common.tplvalues.render" ( dict "value" .Values.worker.podAnnotations "context" $ ) | nindent 8 }}
{{- end }}
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- if (not .Values.existingSecret) }}
checksum/secr
gitextract_jmg13inm/ ├── .checkov.yaml ├── .editorconfig ├── .flake8 ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── config.yml │ │ └── feature_request.yml │ ├── dependabot.yml │ ├── renovate.json │ └── workflows/ │ ├── analysis.yml │ ├── auto-merge.yml │ ├── ci.yml │ ├── lint.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .markdownlint.yaml ├── LICENSE ├── README.md ├── charts/ │ ├── netbox/ │ │ ├── .helmignore │ │ ├── Chart.yaml │ │ ├── README.md │ │ ├── ci/ │ │ │ ├── default-values.yaml │ │ │ ├── ingress-metrics-values.yaml │ │ │ └── ldap-values.yaml │ │ ├── docs/ │ │ │ ├── auth.md │ │ │ ├── extra.md │ │ │ ├── migrate.md │ │ │ └── prod.md │ │ ├── files/ │ │ │ ├── configuration.py │ │ │ └── ldap_config.py │ │ ├── templates/ │ │ │ ├── NOTES.txt │ │ │ ├── _helpers.tpl │ │ │ ├── configmap.yaml │ │ │ ├── cronjob.yaml │ │ │ ├── deployment.yaml │ │ │ ├── extra-list.yaml │ │ │ ├── granian-servicemonitor.yaml │ │ │ ├── hpa.yaml │ │ │ ├── httproute.yaml │ │ │ ├── ingress.yaml │ │ │ ├── pdb.yaml │ │ │ ├── pvc.yaml │ │ │ ├── role.yaml │ │ │ ├── rolebinding.yaml │ │ │ ├── secret.yaml │ │ │ ├── service.yaml │ │ │ ├── serviceaccount.yaml │ │ │ ├── servicemonitor.yaml │ │ │ ├── tests/ │ │ │ │ └── test-connection.yaml │ │ │ └── worker/ │ │ │ ├── deployment.yaml │ │ │ ├── hpa.yaml │ │ │ └── pdb.yaml │ │ ├── values.schema.json │ │ └── values.yaml │ └── netbox-operator/ │ ├── .helmignore │ ├── Chart.yaml │ ├── README.md │ ├── ci/ │ │ └── default-values.yaml │ ├── crds/ │ │ ├── ipaddressclaims.yaml │ │ ├── ipaddresses.yaml │ │ ├── iprangeclaims.yaml │ │ ├── ipranges.yaml │ │ ├── prefixclaims.yaml │ │ └── prefixes.yaml │ ├── templates/ │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── deployment.yaml │ │ ├── leaderelect/ │ │ │ ├── role.yaml │ │ │ └── rolebinding.yaml │ │ ├── secret.yaml │ │ ├── serviceaccount.yaml │ │ └── servicemonitor.yaml │ └── values.yaml ├── config.yaml └── pyproject.toml
SYMBOL INDEX (6 symbols across 2 files) FILE: charts/netbox/files/configuration.py function _deep_merge (line 14) | def _deep_merge(source, destination): function _load_yaml (line 27) | def _load_yaml() -> None: function _read_secret (line 40) | def _read_secret(secret_name: str, secret_key: str, default: str | None ... FILE: charts/netbox/files/ldap_config.py function _load_yaml (line 16) | def _load_yaml() -> None: function _read_secret (line 23) | def _read_secret(secret_name: str, secret_key: str, default: str | None ... function _import_group_type (line 37) | def _import_group_type(group_type_name: str) -> Any | None:
Condensed preview — 79 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (449K chars).
[
{
"path": ".checkov.yaml",
"chars": 136,
"preview": "directory:\n - charts\nskip-path:\n - /\\w+/charts\nevaluate-variables: true\nframework:\n - helm\ncompact: true\nquiet: true\n"
},
{
"path": ".editorconfig",
"chars": 232,
"preview": "# editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_"
},
{
"path": ".flake8",
"chars": 141,
"preview": "[flake8]\nmax-line-length = 100\nextend-ignore = E203, W503\nper-file-ignores =\n charts/netbox/files/*:E131,E251,E266,E302"
},
{
"path": ".gitattributes",
"chars": 263,
"preview": "# https://git-scm.com/docs/gitattributes\n\n# Auto detect text files and perform LF normalization\n* text=auto eol=lf\n\n# Co"
},
{
"path": ".github/FUNDING.yml",
"chars": 120,
"preview": "# https://docs.github.com/articles/displaying-a-sponsor-button-in-your-repository\n\ngithub:\n - RangerRick\n - LeoColomb\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 2659,
"preview": "name: 🐛 Bug Report\ndescription: Create a report about a malfunction of the Helm chart setup\nlabels:\n - bug\nbody:\n - ty"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 612,
"preview": "# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 1314,
"preview": "name: ✨ Feature Request\ndescription: Propose a new NetBox feature or enhancement\nlabels:\n - enhancement\nbody:\n - type:"
},
{
"path": ".github/dependabot.yml",
"chars": 245,
"preview": "# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabo"
},
{
"path": ".github/renovate.json",
"chars": 873,
"preview": "{\n \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n \"extends\": [\n \"config:recommended\",\n \":confi"
},
{
"path": ".github/workflows/analysis.yml",
"chars": 653,
"preview": "# https://docs.github.com/actions\n\nname: Analysis\n\non:\n push:\n branches:\n - main\n pull_request:\n branches:\n"
},
{
"path": ".github/workflows/auto-merge.yml",
"chars": 896,
"preview": "# https://docs.github.com/actions\n\nname: Auto-merge\n\non:\n pull_request_target:\n workflow_call:\n\npermissions:\n pull-re"
},
{
"path": ".github/workflows/ci.yml",
"chars": 1576,
"preview": "# yamllint disable rule:document-start\n# https://docs.github.com/actions\n\nname: CI\n\non:\n push:\n branches:\n - ma"
},
{
"path": ".github/workflows/lint.yml",
"chars": 1250,
"preview": "# https://docs.github.com/actions\n\nname: Lint Code Base\n\non:\n push:\n branches-ignore: [main]\n pull_request:\n bra"
},
{
"path": ".github/workflows/release.yml",
"chars": 2207,
"preview": "# yamllint disable rule:document-start\n# https://docs.github.com/actions\n\nname: Release\n\non:\n workflow_call:\n secret"
},
{
"path": ".github/workflows/test.yml",
"chars": 1246,
"preview": "# yamllint disable rule:document-start\n# https://docs.github.com/actions\n\nname: Test\n\non:\n workflow_call:\n inputs:\n "
},
{
"path": ".gitignore",
"chars": 378,
"preview": "# https://git-scm.com/docs/gitignore\n\n# General files\npkg/*\n*.pyc\n.project\n/.bin\n/_test/secrets/*.json\n\n# macOS\n._*\n.DS_"
},
{
"path": ".markdownlint.yaml",
"chars": 53,
"preview": "default: true\nMD013: false\nMD031: false\nMD060: false\n"
},
{
"path": "LICENSE",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 2522,
"preview": "# Netbox Helm Charts\n\n> The official [Helm](https://helm.sh) charts repository for [Netbox](https://netbox.dev).\n\n[ is an IP address management (IPAM) and\ndata center infrastructure management (DCI"
},
{
"path": "charts/netbox/ci/default-values.yaml",
"chars": 0,
"preview": ""
},
{
"path": "charts/netbox/ci/ingress-metrics-values.yaml",
"chars": 51,
"preview": "ingress:\n enabled: true\n\nmetrics:\n enabled: true\n"
},
{
"path": "charts/netbox/ci/ldap-values.yaml",
"chars": 883,
"preview": "remoteAuth:\n enabled: true\n backends:\n - netbox.authentication.LDAPBackend\n\n ldap:\n serverUri: \"ldap://ldap.for"
},
{
"path": "charts/netbox/docs/auth.md",
"chars": 8843,
"preview": "# Authentication Options\n\n## Using SSO\n\nYou can configure different SSO backends with `remoteAuth`.\nThe implementation i"
},
{
"path": "charts/netbox/docs/extra.md",
"chars": 2213,
"preview": "# Extra Configuration\n\n## Overview\n\nAny additional configuration setting can be passed in the chart\nvalues to be loaded "
},
{
"path": "charts/netbox/docs/migrate.md",
"chars": 1298,
"preview": "# Migration Guide\n\nFor major version updates (5.0.0, 6.0.0, etc.), see the release notes for detailed migration informat"
},
{
"path": "charts/netbox/docs/prod.md",
"chars": 3849,
"preview": "# Production Considerations\n\n## Database Recommendation\n\nWe recommend using separate external PostgreSQL and Key-Value i"
},
{
"path": "charts/netbox/files/configuration.py",
"chars": 2944,
"preview": "\"\"\"\nThis file serves as a base configuration for Netbox\nhttps://netboxlabs.com/docs/netbox/en/stable/configuration/\n\"\"\"\n"
},
{
"path": "charts/netbox/files/ldap_config.py",
"chars": 3032,
"preview": "\"\"\"\nThis file serves as a LDAP configuration for Netbox\nhttps://netboxlabs.com/docs/netbox/en/stable/installation/6-ldap"
},
{
"path": "charts/netbox/templates/NOTES.txt",
"chars": 2566,
"preview": "CHART NAME: {{ .Chart.Name }}\nCHART VERSION: {{ .Chart.Version }}\nAPP VERSION: {{ .Chart.AppVersion }}\n\n** Please be "
},
{
"path": "charts/netbox/templates/_helpers.tpl",
"chars": 8585,
"preview": "{{/* vim: set filetype=mustache: */}}\n\n{{/*\nReturn the proper image name\n*/}}\n{{- define \"netbox.image\" -}}\n{{- include "
},
{
"path": "charts/netbox/templates/configmap.yaml",
"chars": 12520,
"preview": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: {{ include \"common.names.fullname\" . }}\n namespace: {{ include \"common"
},
{
"path": "charts/netbox/templates/cronjob.yaml",
"chars": 11060,
"preview": "{{- if .Values.housekeeping.enabled -}}\napiVersion: batch/v1\nkind: CronJob\nmetadata:\n name: {{ printf \"%s-housekeeping\""
},
{
"path": "charts/netbox/templates/deployment.yaml",
"chars": 15332,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: {{ include \"common.names.fullname\" . }}\n namespace: {{ include \""
},
{
"path": "charts/netbox/templates/extra-list.yaml",
"chars": 115,
"preview": "{{ range .Values.extraDeploy }}\n---\n{{ include \"common.tplvalues.render\" (dict \"value\" . \"context\" $) }}\n{{ end }}\n"
},
{
"path": "charts/netbox/templates/granian-servicemonitor.yaml",
"chars": 2233,
"preview": "{{- if and .Values.metrics.granian.enabled .Values.metrics.granian.serviceMonitor.enabled }}\napiVersion: monitoring.core"
},
{
"path": "charts/netbox/templates/hpa.yaml",
"chars": 2866,
"preview": "{{- if .Values.autoscaling.enabled }}\napiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n name: {{ incl"
},
{
"path": "charts/netbox/templates/httproute.yaml",
"chars": 1217,
"preview": "{{- if .Values.httpRoute.enabled -}}\napiVersion: gateway.networking.k8s.io/v1\nkind: HTTPRoute\nmetadata:\n name: {{ inclu"
},
{
"path": "charts/netbox/templates/ingress.yaml",
"chars": 1455,
"preview": "{{- if .Values.ingress.enabled -}}\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n name: {{ include \"common.n"
},
{
"path": "charts/netbox/templates/pdb.yaml",
"chars": 987,
"preview": "{{- if and .Values.pdb.enabled (or .Values.pdb.minAvailable .Values.pdb.maxUnavailable) }}\napiVersion: policy/v1\nkind: P"
},
{
"path": "charts/netbox/templates/pvc.yaml",
"chars": 3794,
"preview": "{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}\n---\nkind: PersistentVolumeClaim\napiVer"
},
{
"path": "charts/netbox/templates/role.yaml",
"chars": 904,
"preview": "{{- if .Values.rbac.create }}\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n name: {{ include \"common.n"
},
{
"path": "charts/netbox/templates/rolebinding.yaml",
"chars": 774,
"preview": "{{- if .Values.rbac.create }}\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n name: {{ include \"c"
},
{
"path": "charts/netbox/templates/secret.yaml",
"chars": 3847,
"preview": "{{- if not .Values.existingSecret }}\n---\napiVersion: v1\nkind: Secret\nmetadata:\n name: {{ include \"common.secrets.name\" "
},
{
"path": "charts/netbox/templates/service.yaml",
"chars": 3295,
"preview": "apiVersion: v1\nkind: Service\nmetadata:\n name: {{ include \"common.names.fullname\" . }}\n namespace: {{ include \"common.n"
},
{
"path": "charts/netbox/templates/serviceaccount.yaml",
"chars": 775,
"preview": "{{- if .Values.serviceAccount.create -}}\napiVersion: v1\nkind: ServiceAccount\nautomountServiceAccountToken: {{ .Values.se"
},
{
"path": "charts/netbox/templates/servicemonitor.yaml",
"chars": 2052,
"preview": "{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }}\napiVersion: monitoring.coreos.com/v1\nkind: "
},
{
"path": "charts/netbox/templates/tests/test-connection.yaml",
"chars": 1271,
"preview": "apiVersion: v1\nkind: Pod\nmetadata:\n name: {{ printf \"%s-test-connection\" (include \"common.names.fullname\" .) | trunc 63"
},
{
"path": "charts/netbox/templates/worker/deployment.yaml",
"chars": 13123,
"preview": "{{- if .Values.worker.enabled }}\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: {{ printf \"%s-worker\" (include \""
},
{
"path": "charts/netbox/templates/worker/hpa.yaml",
"chars": 3103,
"preview": "{{- if and .Values.worker.enabled .Values.worker.autoscaling.enabled }}\napiVersion: autoscaling/v2\nkind: HorizontalPodAu"
},
{
"path": "charts/netbox/templates/worker/pdb.yaml",
"chars": 1116,
"preview": "{{- if and .Values.worker.enabled .Values.worker.pdb.enabled (or .Values.worker.pdb.minAvailable .Values.worker.pdb.maxU"
},
{
"path": "charts/netbox/values.schema.json",
"chars": 45635,
"preview": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"title\": \"Netbox Helm Chart Schema\",\n \"type\": \"object\""
},
{
"path": "charts/netbox/values.yaml",
"chars": 75777,
"preview": "# Default values for NetBox.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\n## "
},
{
"path": "charts/netbox-operator/.helmignore",
"chars": 443,
"preview": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation"
},
{
"path": "charts/netbox-operator/Chart.yaml",
"chars": 1242,
"preview": "apiVersion: v2\nname: netbox-operator\nversion: 1.2.65\n# renovate: image=ghcr.io/netbox-community/netbox-operator\nappVersi"
},
{
"path": "charts/netbox-operator/README.md",
"chars": 1131,
"preview": "# NetBox Operator\n\n[Operator](https://github.com/netbox-community/netbox-operator) to manage [NetBox](https://netbox.dev"
},
{
"path": "charts/netbox-operator/ci/default-values.yaml",
"chars": 12,
"preview": "https: true\n"
},
{
"path": "charts/netbox-operator/crds/ipaddressclaims.yaml",
"chars": 9417,
"preview": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuild"
},
{
"path": "charts/netbox-operator/crds/ipaddresses.yaml",
"chars": 9070,
"preview": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuild"
},
{
"path": "charts/netbox-operator/crds/iprangeclaims.yaml",
"chars": 11105,
"preview": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuild"
},
{
"path": "charts/netbox-operator/crds/ipranges.yaml",
"chars": 9651,
"preview": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuild"
},
{
"path": "charts/netbox-operator/crds/prefixclaims.yaml",
"chars": 12490,
"preview": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuild"
},
{
"path": "charts/netbox-operator/crds/prefixes.yaml",
"chars": 9601,
"preview": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuild"
},
{
"path": "charts/netbox-operator/templates/NOTES.txt",
"chars": 103,
"preview": "CHART NAME: {{ .Chart.Name }}\nCHART VERSION: {{ .Chart.Version }}\nAPP VERSION: {{ .Chart.AppVersion }}\n"
},
{
"path": "charts/netbox-operator/templates/_helpers.tpl",
"chars": 917,
"preview": "{{/* vim: set filetype=mustache: */}}\n\n{{/*\nCreate the name of the service account to use\n*/}}\n{{- define \"netbox-operat"
},
{
"path": "charts/netbox-operator/templates/clusterrole.yaml",
"chars": 1318,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n name: {{ include \"common.names.fullname\" . }}\n l"
},
{
"path": "charts/netbox-operator/templates/clusterrolebinding.yaml",
"chars": 694,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n name: {{ include \"common.names.fullname\" ."
},
{
"path": "charts/netbox-operator/templates/deployment.yaml",
"chars": 7389,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: {{ include \"common.names.fullname\" . }}\n namespace: {{ include \""
},
{
"path": "charts/netbox-operator/templates/leaderelect/role.yaml",
"chars": 977,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n name: {{ printf \"%s-leader-election\" (include \"common.na"
},
{
"path": "charts/netbox-operator/templates/leaderelect/rolebinding.yaml",
"chars": 909,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n name: {{ printf \"%s-leader-election\" (include \"co"
},
{
"path": "charts/netbox-operator/templates/secret.yaml",
"chars": 648,
"preview": "{{- if not (or .Values.netbox.enabled .Values.auth.existingSecret) }}\napiVersion: v1\nkind: Secret\nmetadata:\n name: {{ i"
},
{
"path": "charts/netbox-operator/templates/serviceaccount.yaml",
"chars": 783,
"preview": "{{- if .Values.serviceAccount.create }}\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: {{ include \"netbox-operato"
},
{
"path": "charts/netbox-operator/templates/servicemonitor.yaml",
"chars": 2189,
"preview": "{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }}\napiVersion: monitoring.coreos.com/v1\nkind: "
},
{
"path": "charts/netbox-operator/values.yaml",
"chars": 15155,
"preview": "# Default values for NetBox Operator.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templa"
},
{
"path": "config.yaml",
"chars": 292,
"preview": "owner: netbox-community\nrepo: netbox-chart\nremote: origin\ntarget-branch: main\nsign: true\nkey: builds@netboxlabs.com\nkeyr"
},
{
"path": "pyproject.toml",
"chars": 499,
"preview": "[tool.black]\nline_length = 100\ntarget-version = [\"py38\"]\ninclude = '\\.pyi?$'\nexclude = '''\n(\n /(\n \\.git\n | \\.ve"
}
]
About this extraction
This page contains the full source code of the bootc/netbox-chart GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 79 files (416.2 KB), approximately 96.3k tokens, and a symbol index with 6 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.