From 4f8727db6273dc51cc00d783750884283b22767b Mon Sep 17 00:00:00 2001 From: Mateusz Urbanek Date: Sun, 12 May 2024 16:55:03 +0200 Subject: [PATCH] feat(controller): initial controller enabler (#4) ## Description This pull request implements initial controller, as well as adds docs and image building. --------- Signed-off-by: Mateusz Urbanek --- .commitlintrc.mjs | 7 + .dockerignore | 3 + .github/ISSUE_TEMPLATE/bug_report.yaml | 20 + .github/PULL_REQUEST_TEMPLATE.md | 12 + .../workflows/{image.yaml => image-docs.yaml} | 25 +- .gitignore | 161 +++ Dockerfile | 2 +- Makefile | 24 +- README.md | 73 +- api/v1alpha1/groupversion_info.go | 2 +- api/v1alpha1/lkeclusterconfig_types.go | 35 +- api/v1alpha1/zz_generated.deepcopy.go | 43 +- cmd/main.go | 2 +- .../lke.anza-labs.dev_lkeclusterconfigs.yaml | 82 +- docs/.crd-ref-docs.yaml | 13 + docs/.gitignore | 160 +++ docs/__init__.py | 0 docs/assets/logo.png | Bin 0 -> 15421 bytes docs/index.md | 7 + docs/overrides/main.html | 8 + docs/reference/out.md | 107 ++ go.mod | 9 +- go.sum | 14 + hack/__init__.py | 0 hack/boilerplate.go.txt | 4 +- hack/publish.py | 114 ++ hack/tools.go | 1 + hack/utils/__init__.py | 1 + hack/utils/logging.py | 34 + internal/controller/common.go | 25 + internal/controller/lkeclusterconfig.go | 171 ++- .../controller/lkeclusterconfig_controller.go | 49 +- internal/controller/lkeclusterconfig_test.go | 17 + internal/errors/errors.go | 32 + internal/lkeclient/lkeclient.go | 2 +- internal/lkeclient/traced/README.md | 49 + internal/lkeclient/traced/tracedclient.gen.go | 342 ++++++ internal/version/version.go | 10 +- mkdocs.yml | 69 ++ poetry.lock | 980 ++++++++++++++++++ pyproject.toml | 31 + test/base/apply.yaml | 12 + test/base/assert.yaml | 14 + 43 files changed, 2676 insertions(+), 90 deletions(-) create mode 100644 .commitlintrc.mjs create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md rename .github/workflows/{image.yaml => image-docs.yaml} (57%) create mode 100644 docs/.crd-ref-docs.yaml create mode 100644 docs/.gitignore create mode 100644 docs/__init__.py create mode 100644 docs/assets/logo.png create mode 100644 docs/index.md create mode 100644 docs/overrides/main.html create mode 100644 docs/reference/out.md create mode 100644 hack/__init__.py create mode 100644 hack/publish.py create mode 100644 hack/utils/__init__.py create mode 100644 hack/utils/logging.py create mode 100644 internal/controller/common.go create mode 100644 internal/controller/lkeclusterconfig_test.go create mode 100644 internal/errors/errors.go create mode 100644 internal/lkeclient/traced/README.md create mode 100644 internal/lkeclient/traced/tracedclient.gen.go create mode 100644 mkdocs.yml create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/.commitlintrc.mjs b/.commitlintrc.mjs new file mode 100644 index 0000000..4851c75 --- /dev/null +++ b/.commitlintrc.mjs @@ -0,0 +1,7 @@ +export default { + extends: ['@commitlint/config-conventional'], + rules: { + 'body-max-line-length': [0], + 'footer-max-line-length': [0], + }, +} diff --git a/.dockerignore b/.dockerignore index be4d35b..cc69833 100644 --- a/.dockerignore +++ b/.dockerignore @@ -21,3 +21,6 @@ docs/ # GitHub configs .github/ + +# Poetry env +.venv diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000..29b48ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,20 @@ +name: Bug Report +description: You encountered bug? Unexpected behavior? Open this one. +title: "[BUG]: " +labels: + - kind/bug +body: + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also, what did you expect to happen? + placeholder: Put your description here. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: Text diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4ce93c9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +## Description +<!-- +What code changes are made? +What problem does this PR addresses, or what feature this PR adds? +--> +This pull request... + +<!-- +Usage: `Resolves #<issue number>`, or `Resolves <link to the issue>`. +If PR is about `failing-tests`, please post the related tests in a comment and do not use `Resolves` +--> +Resolves # diff --git a/.github/workflows/image.yaml b/.github/workflows/image-docs.yaml similarity index 57% rename from .github/workflows/image.yaml rename to .github/workflows/image-docs.yaml index 458530b..f4ca46b 100644 --- a/.github/workflows/image.yaml +++ b/.github/workflows/image-docs.yaml @@ -1,12 +1,14 @@ -name: image +name: image-docs on: push: + branches: + - "main" tags: - 'v*' permissions: - contents: read + contents: write packages: write jobs: @@ -30,3 +32,22 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: ghcr.io/${{ github.event.repository.owner.name }}/lke-operator:${{ github.ref_name }} + build-args: VERSION=${{ github.ref_name }} + + release-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: fregante/setup-git-user@v2 + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + check-latest: true + - run: | + pip install poetry + - run: | + poetry install + - run: | + poetry run publish --version "${{ github.ref_name }}" diff --git a/.gitignore b/.gitignore index 7f7b185..1f7f682 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,164 @@ go.work # generated files dist/ + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/Dockerfile b/Dockerfile index 958302f..c019955 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,7 +54,7 @@ USER 65532:65532 HEALTHCHECK NONE # Add labels. -ARG VERSION=canary +ARG VERSION=dev ## Standard opencontainers labels. LABEL org.opencontainers.image.title="lke-operator" diff --git a/Makefile b/Makefile index e7af4e9..aa9bbff 100644 --- a/Makefile +++ b/Makefile @@ -47,8 +47,17 @@ manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and Cust $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases .PHONY: generate -generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. +generate: controller-gen gowrap ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + go generate ./... + +.PHONY: api-docs +api-docs: crd-ref-docs ## Generate API Reference documentation. + $(CRD_REF_DOCS) \ + --config=./docs/.crd-ref-docs.yaml \ + --source-path=./api/ \ + --renderer=markdown \ + --output-path=./docs/reference/ .PHONY: fmt fmt: ## Run go fmt against code. @@ -128,11 +137,14 @@ CHAINSAW ?= $(LOCALBIN)/chainsaw-$(CHAINSAW_VERSION) KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION) CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION) GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION) +CRD_REF_DOCS = $(LOCALBIN)/crd-ref-docs-$(CRD_REF_DOCS_VERSION) +GOWRAP = $(GOBIN)/gowrap ## Tool Versions CHAINSAW_VERSION ?= $(shell grep 'github.com/kyverno/chainsaw' ./go.mod | cut -d ' ' -f 2) CONTROLLER_TOOLS_VERSION ?= $(shell grep 'sigs.k8s.io/controller-tools' ./go.mod | cut -d ' ' -f 2) GOLANGCI_LINT_VERSION ?= $(shell grep 'github.com/golangci/golangci-lint' ./go.mod | cut -d ' ' -f 2) +CRD_REF_DOCS_VERSION ?= $(shell grep 'github.com/elastic/crd-ref-docs' ./go.mod | cut -d ' ' -f 2) KUSTOMIZE_VERSION ?= $(shell grep 'sigs.k8s.io/kustomize/kustomize/v5' ./go.mod | cut -d ' ' -f 2) .PHONY: kustomize @@ -155,6 +167,16 @@ golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. $(GOLANGCI_LINT): $(LOCALBIN) $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION}) +.PHONY: crd-ref-docs +crd-ref-docs: $(CRD_REF_DOCS) ## Download crd-ref-docs locally if necessary. +$(CRD_REF_DOCS): $(LOCALBIN) + $(call go-install-tool,$(CRD_REF_DOCS),github.com/elastic/crd-ref-docs,${CRD_REF_DOCS_VERSION}) + +.PHONY: gowrap +gowrap: $(GOWRAP) +$(GOWRAP): + GOBIN=$(GOBIN) go install github.com/hexdigest/gowrap/cmd/gowrap@latest + # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary (ideally with version) # $2 - package url which can be installed diff --git a/README.md b/README.md index 5f10bf8..f5ae9c0 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,85 @@ # lke-operator +- [lke-operator](#lke-operator) + - [Overview](#overview) + - [Description](#description) + - [Contributing](#contributing) + - [Development](#development) + - [Documentation](#documentation) + - [Developing](#developing) + - [Setting Up Environment](#setting-up-environment) + - [Code Formatting and Linting](#code-formatting-and-linting) + - [Previewing Documentation Locally](#previewing-documentation-locally) + - [Publishing](#publishing) + - [Automated Release from main branch](#automated-release-from-main-branch) + - [Manual Release from Main Branch](#manual-release-from-main-branch) + - [License](#license) + ## Overview The lke-operator is a Kubernetes operator designed to manage Linode Kubernetes Engine (LKE) clusters. It automates the provisioning, scaling, and management of LKE clusters, simplifying the deployment and maintenance process for Kubernetes workloads on Linode's infrastructure. ## Description The lke-operator streamlines the deployment and management of LKE clusters. It allows users to define their desired LKE cluster configuration using Kubernetes custom resources, which are then reconciled by the operator to ensure the actual cluster matches the desired state. + +## Contributing + +### Development + +The development of the lke-operator requires the following tools: +- `go` +- `make` +- `docker` + +Running any `make` target will install any additional necessary tools required by that target if missing. + +## Documentation + +### Developing + +#### Setting Up Environment + +Ensure you have Python and Poetry installed on your system. + +```sh +poetry install +``` + +#### Code Formatting and Linting + +To ensure code consistency and quality, use the following commands: + +```sh +poetry run black . +poetry run isort --profile=black . +poetry run mypy . +``` + +#### Previewing Documentation Locally + +To preview the documentation locally, run the following command: + +```sh +poetry run mkdocs serve +``` + +### Publishing + +#### Automated Release from main branch + +Each commit to the `main` branch is automatically released to the `main` tag on the page. + +#### Manual Release from Main Branch + +To manually release from the `main` branch, follow these steps: + +```sh +poetry run publish +``` + ## License -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go index 0e13b1a..0eaeaec 100644 --- a/api/v1alpha1/groupversion_info.go +++ b/api/v1alpha1/groupversion_info.go @@ -1,5 +1,5 @@ /* -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/api/v1alpha1/lkeclusterconfig_types.go b/api/v1alpha1/lkeclusterconfig_types.go index 71e568f..47c89d1 100644 --- a/api/v1alpha1/lkeclusterconfig_types.go +++ b/api/v1alpha1/lkeclusterconfig_types.go @@ -1,5 +1,5 @@ /* -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,8 +28,7 @@ type LKEClusterConfigSpec struct { // TokenSecretRef references the Kubernetes secret that stores the Linode API token. // If not provided, then default token will be used. - // +kubebuilder:validation:optional - TokenSecretRef *SecretRef `json:"string,omitempty"` + TokenSecretRef SecretRef `json:"tokenSecretRef"` // HighAvailability specifies whether the LKE cluster should be configured for high // availability. @@ -43,7 +42,7 @@ type LKEClusterConfigSpec struct { // KubernetesVersion indicates the Kubernetes version of the LKE cluster. // +kubebuilder:validation:optional - // +kubebuilder:default="latest" + // +kubebuilder:default=latest KubernetesVersion *string `json:"kubernetesVersion,omitempty"` } @@ -56,14 +55,12 @@ type SecretRef struct { // LKENodePool represents a pool of nodes within the LKE cluster. type LKENodePool struct { // NodeCount specifies the number of nodes in the node pool. - // +kubebuilder:validation:optional // +kubebuilder:default=3 - NodeCount *int `json:"nodeCount,omitempty"` + NodeCount int `json:"nodeCount"` // LinodeType specifies the Linode instance type for the nodes in the pool. - // +kubebuilder:validation:optional - // +kubebuilder:default="g6-standard-1" - LinodeType *string `json:"linodeType,omitempty"` + // +kubebuilder:default=g6-standard-1 + LinodeType string `json:"linodeType"` // Autoscaler specifies the autoscaling configuration for the node pool. // +kubebuilder:validation:optional @@ -87,11 +84,12 @@ type LKENodePoolAutoscaler struct { type LKEClusterConfigStatus struct { // Phase represents the current phase of the LKE cluster. // +kubebuilder:validation:optional - Phase string `json:"phase,omitempty"` + // +kubebuilder:default=Unknown + Phase *Phase `json:"phase,omitempty"` // ClusterID contains the ID of the provisioned LKE cluster. // +kubebuilder:validation:optional - ClusterID int `json:"clusterID,omitempty"` + ClusterID *int `json:"clusterID,omitempty"` // NodePoolsIDs contains the IDs of the provisioned node pools within the LKE cluster. // +kubebuilder:validation:optional @@ -99,9 +97,22 @@ type LKEClusterConfigStatus struct { // FailureMessage contains an optional failure message for the LKE cluster. // +kubebuilder:validation:optional - FailureMessage string `json:"failureMessage,omitempty"` + FailureMessage *string `json:"failureMessage,omitempty"` } +// +kubebuilder:validation:Enum=Active;Deleting;Provisioning;Unknown;Updating +type Phase string + +const ( + PhaseActive Phase = "Active" + PhaseDeleting Phase = "Deleting" + PhaseProvisioning Phase = "Provisioning" + PhaseUpdating Phase = "Updating" + PhaseUnknown Phase = "Unknown" +) + +//+kubebuilder:object:root=true + // LKEClusterConfig is the Schema for the lkeclusterconfigs API. type LKEClusterConfig struct { metav1.TypeMeta `json:",inline"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 24422aa..9936e9f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated /* -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -86,6 +86,7 @@ func (in *LKEClusterConfigList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LKEClusterConfigSpec) DeepCopyInto(out *LKEClusterConfigSpec) { *out = *in + out.TokenSecretRef = in.TokenSecretRef if in.HighAvailability != nil { in, out := &in.HighAvailability, &out.HighAvailability *out = new(bool) @@ -118,11 +119,26 @@ func (in *LKEClusterConfigSpec) DeepCopy() *LKEClusterConfigSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LKEClusterConfigStatus) DeepCopyInto(out *LKEClusterConfigStatus) { *out = *in + if in.Phase != nil { + in, out := &in.Phase, &out.Phase + *out = new(Phase) + **out = **in + } + if in.ClusterID != nil { + in, out := &in.ClusterID, &out.ClusterID + *out = new(int) + **out = **in + } if in.NodePoolsIDs != nil { in, out := &in.NodePoolsIDs, &out.NodePoolsIDs *out = make([]int, len(*in)) copy(*out, *in) } + if in.FailureMessage != nil { + in, out := &in.FailureMessage, &out.FailureMessage + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LKEClusterConfigStatus. @@ -138,16 +154,6 @@ func (in *LKEClusterConfigStatus) DeepCopy() *LKEClusterConfigStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LKENodePool) DeepCopyInto(out *LKENodePool) { *out = *in - if in.NodeCount != nil { - in, out := &in.NodeCount, &out.NodeCount - *out = new(int) - **out = **in - } - if in.LinodeType != nil { - in, out := &in.LinodeType, &out.LinodeType - *out = new(string) - **out = **in - } if in.Autoscaler != nil { in, out := &in.Autoscaler, &out.Autoscaler *out = new(LKENodePoolAutoscaler) @@ -179,3 +185,18 @@ func (in *LKENodePoolAutoscaler) DeepCopy() *LKENodePoolAutoscaler { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretRef) DeepCopyInto(out *SecretRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretRef. +func (in *SecretRef) DeepCopy() *SecretRef { + if in == nil { + return nil + } + out := new(SecretRef) + in.DeepCopyInto(out) + return out +} diff --git a/cmd/main.go b/cmd/main.go index 7e4dadd..e21cf87 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,5 +1,5 @@ /* -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/config/crd/bases/lke.anza-labs.dev_lkeclusterconfigs.yaml b/config/crd/bases/lke.anza-labs.dev_lkeclusterconfigs.yaml index 7d974f2..30c5bf0 100644 --- a/config/crd/bases/lke.anza-labs.dev_lkeclusterconfigs.yaml +++ b/config/crd/bases/lke.anza-labs.dev_lkeclusterconfigs.yaml @@ -11,25 +11,13 @@ spec: kind: LKEClusterConfig listKind: LKEClusterConfigList plural: lkeclusterconfigs - shortNames: - - lkecc singular: lkeclusterconfig scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .spec.kubernetesVersion - name: K8sVersion - type: string - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.failureMessage - name: FailureMessage - type: string - name: v1alpha1 + - name: v1alpha1 schema: openAPIV3Schema: - description: LKEClusterConfig is the Schema for the lkeclusterconfigs API + description: LKEClusterConfig is the Schema for the lkeclusterconfigs API. properties: apiVersion: description: |- @@ -49,32 +37,40 @@ spec: metadata: type: object spec: - description: LKEClusterConfigSpec defines the desired state of LKEClusterConfig + description: LKEClusterConfigSpec defines the desired state of an LKEClusterConfig + resource. properties: highAvailability: default: false - description: HighAvailability + description: |- + HighAvailability specifies whether the LKE cluster should be configured for high + availability. type: boolean kubernetesVersion: default: latest - description: KubernetesVersion indicates the kubernetes version of - LKE. + description: KubernetesVersion indicates the Kubernetes version of + the LKE cluster. type: string nodePools: - description: NodePools + description: NodePools contains the specifications for each node pool + within the LKE cluster. items: - description: LKENodePool + description: LKENodePool represents a pool of nodes within the LKE + cluster. properties: autoscaler: - description: Autoscaler + description: Autoscaler specifies the autoscaling configuration + for the node pool. properties: max: - description: Max + description: Max specifies the maximum number of nodes in + the pool. maximum: 100 minimum: 3 type: integer min: - description: Min + description: Min specifies the minimum number of nodes in + the pool. maximum: 100 minimum: 0 type: integer @@ -84,20 +80,28 @@ spec: type: object linodeType: default: g6-standard-1 - description: LinodeType + description: LinodeType specifies the Linode instance type for + the nodes in the pool. type: string nodeCount: default: 3 - description: NodeCount + description: NodeCount specifies the number of nodes in the + node pool. type: integer + required: + - linodeType + - nodeCount type: object minItems: 1 type: array region: - description: Region + description: Region is the geographical region where the LKE cluster + will be provisioned. type: string - string: - description: TokenSecretRef + tokenSecretRef: + description: |- + TokenSecretRef references the Kubernetes secret that stores the Linode API token. + If not provided, then default token will be used. properties: name: type: string @@ -110,28 +114,36 @@ spec: required: - nodePools - region + - tokenSecretRef type: object status: - description: LKEClusterConfigStatus defines the observed state of LKEClusterConfig + description: LKEClusterConfigStatus defines the observed state of an LKEClusterConfig + resource. properties: clusterID: - description: ClusterID + description: ClusterID contains the ID of the provisioned LKE cluster. type: integer failureMessage: description: FailureMessage contains an optional failure message for - the cluster. + the LKE cluster. type: string nodePoolIDs: - description: NodePoolsIDs + description: NodePoolsIDs contains the IDs of the provisioned node + pools within the LKE cluster. items: type: integer type: array phase: - description: Phase represents the current phase of the cluster. + default: Unknown + description: Phase represents the current phase of the LKE cluster. + enum: + - Active + - Deleting + - Provisioning + - Unknown + - Updating type: string type: object type: object served: true storage: true - subresources: - status: {} diff --git a/docs/.crd-ref-docs.yaml b/docs/.crd-ref-docs.yaml new file mode 100644 index 0000000..3839b5b --- /dev/null +++ b/docs/.crd-ref-docs.yaml @@ -0,0 +1,13 @@ +processor: + # RE2 regular expressions describing types that should be excluded from the generated documentation. + ignoreTypes: + - "(LKEClusterConfig)List$" + - "(LKEClusterConfig)Status$" + # RE2 regular expressions describing type fields that should be excluded from the generated documentation. + ignoreFields: + - "status$" + - "TypeMeta$" + +render: + # Version of Kubernetes to use when generating links to Kubernetes API documentation. + kubernetesVersion: 1.30 diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..68bc17f --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,160 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/docs/__init__.py b/docs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9771a793445fdd2c17a1318c81fe58638519ba17 GIT binary patch literal 15421 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 literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..e816f3a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,7 @@ +# lke-operator + +## Overview +The lke-operator is a Kubernetes operator designed to manage Linode Kubernetes Engine (LKE) clusters. It automates the provisioning, scaling, and management of LKE clusters, simplifying the deployment and maintenance process for Kubernetes workloads on Linode's infrastructure. + +## Description +The lke-operator streamlines the deployment and management of LKE clusters. It allows users to define their desired LKE cluster configuration using Kubernetes custom resources, which are then reconciled by the operator to ensure the actual cluster matches the desired state. diff --git a/docs/overrides/main.html b/docs/overrides/main.html new file mode 100644 index 0000000..0af326a --- /dev/null +++ b/docs/overrides/main.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% block outdated %} + You're not viewing the latest version. + <a href="{{ '../' ~ base_url }}"> + <strong>Click here to go to latest.</strong> + </a> +{% endblock %} diff --git a/docs/reference/out.md b/docs/reference/out.md new file mode 100644 index 0000000..2dbe519 --- /dev/null +++ b/docs/reference/out.md @@ -0,0 +1,107 @@ +# API Reference + +## Packages +- [lke.anza-labs.dev/v1alpha1](#lkeanza-labsdevv1alpha1) + + +## lke.anza-labs.dev/v1alpha1 + +Package v1alpha1 contains API Schema definitions for the lke v1alpha1 API group + +### Resource Types +- [LKEClusterConfig](#lkeclusterconfig) + + + +#### LKEClusterConfig + + + +LKEClusterConfig is the Schema for the lkeclusterconfigs API. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `lke.anza-labs.dev/v1alpha1` | | | +| `kind` _string_ | `LKEClusterConfig` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.3/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[LKEClusterConfigSpec](#lkeclusterconfigspec)_ | | | | + + +#### LKEClusterConfigSpec + + + +LKEClusterConfigSpec defines the desired state of an LKEClusterConfig resource. + + + +_Appears in:_ +- [LKEClusterConfig](#lkeclusterconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `region` _string_ | Region is the geographical region where the LKE cluster will be provisioned. | | | +| `tokenSecretRef` _[SecretRef](#secretref)_ | TokenSecretRef references the Kubernetes secret that stores the Linode API token.<br />If not provided, then default token will be used. | | | +| `highAvailability` _boolean_ | HighAvailability specifies whether the LKE cluster should be configured for high<br />availability. | false | | +| `nodePools` _[LKENodePool](#lkenodepool) array_ | NodePools contains the specifications for each node pool within the LKE cluster. | | MinItems: 1 <br /> | +| `kubernetesVersion` _string_ | KubernetesVersion indicates the Kubernetes version of the LKE cluster. | latest | | + + +#### LKENodePool + + + +LKENodePool represents a pool of nodes within the LKE cluster. + + + +_Appears in:_ +- [LKEClusterConfigSpec](#lkeclusterconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `nodeCount` _integer_ | NodeCount specifies the number of nodes in the node pool. | 3 | | +| `linodeType` _string_ | LinodeType specifies the Linode instance type for the nodes in the pool. | g6-standard-1 | | +| `autoscaler` _[LKENodePoolAutoscaler](#lkenodepoolautoscaler)_ | Autoscaler specifies the autoscaling configuration for the node pool. | | | + + +#### LKENodePoolAutoscaler + + + +LKENodePoolAutoscaler represents the autoscaler configuration for a node pool. + + + +_Appears in:_ +- [LKENodePool](#lkenodepool) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `min` _integer_ | Min specifies the minimum number of nodes in the pool. | | Maximum: 100 <br />Minimum: 0 <br /> | +| `max` _integer_ | Max specifies the maximum number of nodes in the pool. | | Maximum: 100 <br />Minimum: 3 <br /> | + + + + +#### SecretRef + + + +SecretRef references a Kubernetes secret. + + + +_Appears in:_ +- [LKEClusterConfigSpec](#lkeclusterconfigspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `namespace` _string_ | | | | +| `name` _string_ | | | | + + diff --git a/go.mod b/go.mod index 338793e..768185b 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,9 @@ go 1.22.3 require ( github.com/linode/linodego v1.33.1 + go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel/trace v1.24.0 + k8s.io/api v0.30.0 k8s.io/apimachinery v0.30.0 k8s.io/client-go v0.30.0 k8s.io/klog/v2 v2.120.1 @@ -13,6 +16,7 @@ require ( // tools require ( github.com/golangci/golangci-lint v1.58.1 + github.com/elastic/crd-ref-docs v0.0.12 github.com/kyverno/chainsaw v0.2.0 sigs.k8s.io/controller-tools v0.14.0 sigs.k8s.io/kustomize/kustomize/v5 v5.4.1 @@ -106,6 +110,7 @@ require ( github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gobuffalo/flect v1.0.2 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-yaml v1.11.3 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -261,12 +266,10 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/sdk v1.23.1 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect go.uber.org/automaxprocs v1.5.3 // indirect @@ -284,6 +287,7 @@ require ( golang.org/x/text v0.15.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.170.0 // indirect google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect @@ -297,7 +301,6 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.4.7 // indirect - k8s.io/api v0.30.0 // indirect k8s.io/apiextensions-apiserver v0.30.0 // indirect k8s.io/apiserver v0.30.0 // indirect k8s.io/component-base v0.30.0 // indirect diff --git a/go.sum b/go.sum index 0d7bca0..9dbcd5d 100644 --- a/go.sum +++ b/go.sum @@ -320,6 +320,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustinkirkland/golang-petname v0.0.0-20240422154211-76c06c4bde6b h1:+0Xqob+onh+4l9TSWmFyZ4JHqGUiCy5P1muyH8Evfpw= github.com/dustinkirkland/golang-petname v0.0.0-20240422154211-76c06c4bde6b/go.mod h1:8AuBTZBRSFqEYBPYULd+NN474/zZBLP+6WeT5S9xlAc= +github.com/elastic/crd-ref-docs v0.0.12 h1:F3seyncbzUz3rT3d+caeYWhumb5ojYQ6Bl0Z+zOp16M= +github.com/elastic/crd-ref-docs v0.0.12/go.mod h1:X83mMBdJt05heJUYiS3T0yJ/JkCuliuhSUNav5Gjo/U= github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -353,6 +355,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk= github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw= @@ -376,6 +380,12 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U= +github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA= github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -408,6 +418,8 @@ github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= +github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= @@ -662,6 +674,8 @@ github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJ github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= github.com/linode/linodego v1.33.1 h1:GcI7ozlHHzZbfthD8edLNInhHjQ452iCwtphza+FJGc= diff --git a/hack/__init__.py b/hack/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index eb0819c..63647fa 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -12,4 +12,4 @@ 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. -*/ \ No newline at end of file +*/ diff --git a/hack/publish.py b/hack/publish.py new file mode 100644 index 0000000..b374ea3 --- /dev/null +++ b/hack/publish.py @@ -0,0 +1,114 @@ +# Copyright 2024 lke-operator contributors. +# +# 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. + +import argparse +import subprocess +import sys + +import semver + +import hack.utils as utils + +logger = utils.setup(__name__) + + +def _parse_version(version: str) -> tuple[str, bool]: + """ + Parses the given version string and returns a short version string and a boolean indicating whether it's a prerelease. + + Args: + version (str): The version string to parse. + + Returns: + Tuple[str, bool]: A tuple containing the short version string and a boolean indicating whether it's a prerelease. + """ + short_version = "" + is_prerelease = True + + if version == "main": + short_version = version + else: + try: + sv = semver.Version.parse(version.removeprefix("v")) + short_version = f"v{sv.major}.{sv.minor}" + is_prerelease = sv.prerelease is not None + except ValueError as e: + logger.warn(e) + + logger.info("%s (is_prerelease: %s)", short_version, is_prerelease) + return short_version, is_prerelease + + +def mike(args: list[str]) -> None: + """ + Runs Mike with the given arguments. + + Args: + args (list[str]): The list of arguments to pass to Mike. + + Raises: + Exception: If Mike command execution returns a non-zero exit code. + """ + rc = subprocess.run( + ["mike"] + args, + stdout=sys.stdout, + stderr=sys.stderr, + ) + if rc.returncode != 0: + raise Exception(rc.stderr) + + +def is_initial() -> bool: + """ + Checks if the current repository state is initial. + + Returns: + bool: True if the repository state is initial, False otherwise. + """ + rc = subprocess.run( + ["git", "show-ref", "--quiet", "refs/heads/gh-pages"], + ) + return rc.returncode != 0 + + +def run(args=sys.argv): + """ + Runs the publish script. + + Args: + args: The arguments to the script. + """ + parser = argparse.ArgumentParser( + prog="publish", + description="Script to build and publish documentation of registry-operator docs", + ) + parser.add_argument( + "--version", + help="Tagged version which should be built", + default="main", + type=str, + required=False, + ) + + args = parser.parse_args(args=args[1:]) + + version, prerelease = _parse_version(version=args.version) + if is_initial(): + mike(["deploy", "--push", "--update-aliases", version, "latest"]) + mike(["set-default", "--push", "latest"]) + else: + if prerelease: + mike(["deploy", "--push", "--update-aliases", version]) + else: + mike(["deploy", "--push", "--update-aliases", version, "latest"]) diff --git a/hack/tools.go b/hack/tools.go index ddc8e36..96c4910 100644 --- a/hack/tools.go +++ b/hack/tools.go @@ -4,6 +4,7 @@ package hack import ( + _ "github.com/elastic/crd-ref-docs" _ "github.com/golangci/golangci-lint/cmd/golangci-lint" _ "github.com/kyverno/chainsaw" _ "sigs.k8s.io/controller-tools/cmd/controller-gen" diff --git a/hack/utils/__init__.py b/hack/utils/__init__.py new file mode 100644 index 0000000..09c02da --- /dev/null +++ b/hack/utils/__init__.py @@ -0,0 +1 @@ +from hack.utils.logging import * diff --git a/hack/utils/logging.py b/hack/utils/logging.py new file mode 100644 index 0000000..0941114 --- /dev/null +++ b/hack/utils/logging.py @@ -0,0 +1,34 @@ +# Copyright 2024 lke-operator contributors. +# +# 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. + +import logging + + +def setup(name: str = __name__) -> logging.Logger: + # Create a logger + logger = logging.getLogger(name) + logger.setLevel(logging.INFO) + + # Create a console handler and set its level + console_handler = logging.StreamHandler() + console_handler.setLevel(logging.INFO) + + # Create a formatter + formatter = logging.Formatter("%(levelname).4s:%(name)s - %(message)s") + console_handler.setFormatter(formatter) + + # Add the console handler to the logger + logger.addHandler(console_handler) + + return logger diff --git a/internal/controller/common.go b/internal/controller/common.go new file mode 100644 index 0000000..7acb5a6 --- /dev/null +++ b/internal/controller/common.go @@ -0,0 +1,25 @@ +/* +Copyright 2024 lke-operator contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +const ( + lkeFinalizer = "lke.anza-labs.dev/finalizer" +) + +func mkptr[T any](t T) *T { + return &t +} diff --git a/internal/controller/lkeclusterconfig.go b/internal/controller/lkeclusterconfig.go index a5f68df..42a33ef 100644 --- a/internal/controller/lkeclusterconfig.go +++ b/internal/controller/lkeclusterconfig.go @@ -1,30 +1,177 @@ +/* +Copyright 2024 lke-operator contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package controller import ( "context" + "encoding/base64" + "errors" + "fmt" "github.com/anza-labs/lke-operator/api/v1alpha1" + internalerrors "github.com/anza-labs/lke-operator/internal/errors" + "github.com/anza-labs/lke-operator/internal/lkeclient" + tracedclient "github.com/anza-labs/lke-operator/internal/lkeclient/traced" + "github.com/anza-labs/lke-operator/internal/version" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/log" ) -type LKEClusterConfigHandler struct{} +const ( + TokenKey = "LINODE_TOKEN" +) -func (h *LKEClusterConfigHandler) OnChange(ctx context.Context, lke *v1alpha1.LKEClusterConfig) (ctrl.Result, error) { - /* - 1. Get Cluster - - If Not Exists: - 1. Create Cluster (return requeue) - - If Exists: - 1. Check state - 2. - */ +// OnChange must be idempotent +func (r *LKEClusterConfigReconciler) OnChange( + ctx context.Context, + lke *v1alpha1.LKEClusterConfig, +) (ctrl.Result, error) { + client, err := r.newLKEClient(ctx, lke.Spec.TokenSecretRef) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to create client: %w", err) + } + + return r.onChange(ctx, client, lke) +} + +func (r *LKEClusterConfigReconciler) onChange( + ctx context.Context, + client lkeclient.Client, + lke *v1alpha1.LKEClusterConfig, +) (ctrl.Result, error) { panic("unimplemented") } -func (h *LKEClusterConfigHandler) OnDelete(ctx context.Context, lke *v1alpha1.LKEClusterConfig) (ctrl.Result, error) { +// OnDelete must be idempotent +func (r *LKEClusterConfigReconciler) OnDelete( + ctx context.Context, + lke *v1alpha1.LKEClusterConfig, +) (ctrl.Result, error) { + client, err := r.newLKEClient(ctx, lke.Spec.TokenSecretRef) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to create client: %w", err) + } + + lke.Status.Phase = mkptr(v1alpha1.PhaseDeleting) + + if err := r.Update(ctx, lke); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to set phase %s: %w", + v1alpha1.PhaseDeleting, + err, + ) + } + + return r.onDelete(ctx, client, lke) +} + +func (r *LKEClusterConfigReconciler) onDelete( + ctx context.Context, + client lkeclient.Client, + lke *v1alpha1.LKEClusterConfig, +) (ctrl.Result, error) { /* 1. Initiate Deleting cluster (return requeue) 2. If cluster is deleted, then return OK */ - panic("unimplemented") + + if lke.Status.ClusterID == nil { + return ctrl.Result{}, internalerrors.ErrNoClusterID + } + + _, err := client.GetLKECluster(ctx, *lke.Status.ClusterID) + if err != nil { + if !errors.Is(err, internalerrors.ErrLinodeNotFound) { + return ctrl.Result{}, fmt.Errorf("failed to get cluster: %w", err) + } + + return ctrl.Result{}, nil + } + + if err = client.DeleteLKECluster(ctx, *lke.Status.ClusterID); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to remove cluster: %w", err) + } + + return ctrl.Result{Requeue: true}, nil +} + +func (r *LKEClusterConfigReconciler) secretFromRef( + ctx context.Context, + ref v1alpha1.SecretRef, +) (*corev1.Secret, error) { + log := log.FromContext(ctx) + + secretRef := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + log.V(8).Info("secret defined, fetching data for client", + "secret", secretRef) + + secret := new(corev1.Secret) + if err := r.Get(ctx, secretRef, secret); err != nil { + return nil, err + } + + return secret, nil +} + +func (r *LKEClusterConfigReconciler) newLKEClient( + ctx context.Context, + ref v1alpha1.SecretRef, +) (lkeclient.Client, error) { + secret, err := r.secretFromRef(ctx, ref) + if err != nil { + return nil, fmt.Errorf("failed to get secret: %w", err) + } + + if secret == nil { + return nil, fmt.Errorf("%w: %s/%s", + internalerrors.ErrNilSecret, + ref.Namespace, + ref.Name, + ) + } + + encodedToken, ok := secret.Data[TokenKey] + if !ok { + return nil, fmt.Errorf("%w: %s/%s (key:%q)", + internalerrors.ErrTokenMissing, + secret.Namespace, + secret.Name, + TokenKey, + ) + } + + token, err := base64.StdEncoding.DecodeString(string(encodedToken)) + if err != nil { + return nil, err + } + + ua := fmt.Sprintf("lke-operator/%s (%s; %s)", + version.Version, + version.OS, + version.Arch, + ) + + return tracedclient.NewClientWithTracing( + lkeclient.New(string(token), ua), + "dynamic_lke_traced_client", + ), nil } diff --git a/internal/controller/lkeclusterconfig_controller.go b/internal/controller/lkeclusterconfig_controller.go index 43a5d8e..49e4cab 100644 --- a/internal/controller/lkeclusterconfig_controller.go +++ b/internal/controller/lkeclusterconfig_controller.go @@ -1,5 +1,5 @@ /* -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" "github.com/anza-labs/lke-operator/api/v1alpha1" @@ -49,7 +50,9 @@ type LKEClusterConfigReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.17.3/pkg/reconcile func (r *LKEClusterConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx).WithName("reconcile") + log := log.FromContext(ctx).WithName("reconcile").WithValues("object.namespaced_name", req) + + log.Info("reconciling") lke := &v1alpha1.LKEClusterConfig{} if err := r.Get(ctx, req.NamespacedName, lke); err != nil { @@ -59,16 +62,52 @@ func (r *LKEClusterConfigReconciler) Reconcile(ctx context.Context, req ctrl.Req log.Info("LKEClusterConfig resource not found, ignoring since object must be deleted") return ctrl.Result{}, nil } + // Error reading the object - requeue the request. log.Error(err, "failed to get LKEClusterConfig") return ctrl.Result{}, err } - if lke.DeletionTimestamp != nil { - return (&LKEClusterConfigHandler{}).OnDelete(ctx, lke) + if !lke.DeletionTimestamp.IsZero() && lke.Status.ClusterID != nil { + res, err := r.OnDelete(ctx, lke) + if err != nil { + log.Error(err, "on LKE deletion failed") + return ctrl.Result{}, err + } + + if !res.Requeue { + log.Info("removing finalizer", + "finalizer", lkeFinalizer) + + // remove our finalizer from the list and update it. + controllerutil.RemoveFinalizer(lke, lkeFinalizer) + if err := r.Update(ctx, lke); err != nil { + log.Error(err, "removing finalizer failed") + return ctrl.Result{}, err + } + } + + return res, nil + } + + if !controllerutil.ContainsFinalizer(lke, lkeFinalizer) { + log.Info("adding finalizer", + "finalizer", lkeFinalizer) + + controllerutil.AddFinalizer(lke, lkeFinalizer) + if err := r.Update(ctx, lke); err != nil { + log.Error(err, "adding finalizer failed") + return ctrl.Result{}, err + } + } + + res, err := r.OnChange(ctx, lke) + if err != nil { + log.Error(err, "on LKE change failed") + return ctrl.Result{}, err } - return (&LKEClusterConfigHandler{}).OnChange(ctx, lke) + return res, nil } // SetupWithManager sets up the controller with the Manager. diff --git a/internal/controller/lkeclusterconfig_test.go b/internal/controller/lkeclusterconfig_test.go new file mode 100644 index 0000000..f92fc92 --- /dev/null +++ b/internal/controller/lkeclusterconfig_test.go @@ -0,0 +1,17 @@ +/* +Copyright 2024 lke-operator contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller diff --git a/internal/errors/errors.go b/internal/errors/errors.go new file mode 100644 index 0000000..18d12c2 --- /dev/null +++ b/internal/errors/errors.go @@ -0,0 +1,32 @@ +/* +Copyright 2024 lke-operator contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package errors + +import ( + "errors" + "net/http" + + "github.com/linode/linodego" +) + +var ( + ErrNilSecret = errors.New("secret is nil") + ErrTokenMissing = errors.New("token is missing from secret") + ErrNoClusterID = errors.New("no cluster ID") + + ErrLinodeNotFound = linodego.Error{Code: http.StatusNotFound} +) diff --git a/internal/lkeclient/lkeclient.go b/internal/lkeclient/lkeclient.go index 4cf8046..5d395bb 100644 --- a/internal/lkeclient/lkeclient.go +++ b/internal/lkeclient/lkeclient.go @@ -1,5 +1,5 @@ /* -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/lkeclient/traced/README.md b/internal/lkeclient/traced/README.md new file mode 100644 index 0000000..1decc55 --- /dev/null +++ b/internal/lkeclient/traced/README.md @@ -0,0 +1,49 @@ +# Traced Client Wrapper + +This package, `tracedclient`, is a generated client wrapper for the Linode Client (LKE method subset). The code is generated using the tool `gowrap` with a specified template for OpenTelemetry instrumentation. + +Code generation streamlines development, reduces boilerplate, and enhances consistency. It boosts productivity by automating repetitive tasks, saves time, and simplifies maintenance. It also minimizes errors and enforces standards. + +## Purpose + +1. **Instrumentation with OpenTelemetry:** The primary purpose of this code is to provide an instrumented version of the Linode COSI driver client with OpenTelemetry spans. This is achieved by adding tracing functionality to various methods in the client. + +2. **Observability:** OpenTelemetry is used for distributed tracing, which helps in observing and understanding how requests propagate through a system, making it easier to identify performance bottlenecks and troubleshoot issues. + +## Code Generation + +The code in this package is generated using the `gowrap` tool. To generate the code, you can use the following commands: + +- **Using `go generate`**: + + ```bash + go generate ./... + ``` + + This command will trigger the `go:generate` directives in the code, causing the `gowrap` tool to generate the necessary files. + + Ensure that you have the `gowrap` tool installed before running the code generation command. + +- **Using Makefile**: + + ```bash + make generate + ``` + + The Makefile target will ensure that the `gowrap` tool is installed. + +## Usage Example + +To use the instrumented client: + +```go +baseClient := lkeclient.NewLinodeClient(token, ua) // Initialize the original LKE client +tracedClient := tracedclient.NewClientWithTracing(baseClient, "instance_id") +``` + +Now, `tracedClient` can be used just like the original client, with the added benefit of OpenTelemetry tracing. + +## Links + +- [gowrap](http://github.com/hexdigest/gowrap): The `gowrap` tool used for code generation. +- [OpenTelemetry](https://opentelemetry.io/): OpenTelemetry project for observability and instrumentation. diff --git a/internal/lkeclient/traced/tracedclient.gen.go b/internal/lkeclient/traced/tracedclient.gen.go new file mode 100644 index 0000000..6fba668 --- /dev/null +++ b/internal/lkeclient/traced/tracedclient.gen.go @@ -0,0 +1,342 @@ +// Code generated by gowrap. DO NOT EDIT. +// template: https://raw.githubusercontent.com/hexdigest/gowrap/6c8f05695fec23df85903a8da0af66ac414e2a63/templates/opentelemetry +// gowrap: http://github.com/hexdigest/gowrap + +package traced + +//go:generate gowrap gen -p github.com/anza-labs/lke-operator/internal/lkeclient -i Client -t https://raw.githubusercontent.com/hexdigest/gowrap/6c8f05695fec23df85903a8da0af66ac414e2a63/templates/opentelemetry -o tracedclient.gen.go -l "" + +import ( + "context" + + "github.com/anza-labs/lke-operator/internal/lkeclient" + "github.com/linode/linodego" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// ClientWithTracing implements lkeclient.Client interface instrumented with opentracing spans +type ClientWithTracing struct { + lkeclient.Client + _instance string + _spanDecorator func(span trace.Span, params, results map[string]interface{}) +} + +// NewClientWithTracing returns ClientWithTracing +func NewClientWithTracing(base lkeclient.Client, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) ClientWithTracing { + d := ClientWithTracing{ + Client: base, + _instance: instance, + } + + if len(spanDecorator) > 0 && spanDecorator[0] != nil { + d._spanDecorator = spanDecorator[0] + } + + return d +} + +// CreateLKECluster implements lkeclient.Client +func (_d ClientWithTracing) CreateLKECluster(ctx context.Context, opts linodego.LKEClusterCreateOptions) (lp1 *linodego.LKECluster, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.CreateLKECluster") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "opts": opts}, map[string]interface{}{ + "lp1": lp1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.CreateLKECluster(ctx, opts) +} + +// CreateLKENodePool implements lkeclient.Client +func (_d ClientWithTracing) CreateLKENodePool(ctx context.Context, clusterID int, opts linodego.LKENodePoolCreateOptions) (lp1 *linodego.LKENodePool, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.CreateLKENodePool") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID, + "opts": opts}, map[string]interface{}{ + "lp1": lp1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.CreateLKENodePool(ctx, clusterID, opts) +} + +// DeleteLKECluster implements lkeclient.Client +func (_d ClientWithTracing) DeleteLKECluster(ctx context.Context, clusterID int) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.DeleteLKECluster") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.DeleteLKECluster(ctx, clusterID) +} + +// DeleteLKENodePool implements lkeclient.Client +func (_d ClientWithTracing) DeleteLKENodePool(ctx context.Context, clusterID int, poolID int) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.DeleteLKENodePool") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID, + "poolID": poolID}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.DeleteLKENodePool(ctx, clusterID, poolID) +} + +// DeleteLKENodePoolNode implements lkeclient.Client +func (_d ClientWithTracing) DeleteLKENodePoolNode(ctx context.Context, clusterID int, nodeID string) (err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.DeleteLKENodePoolNode") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID, + "nodeID": nodeID}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.DeleteLKENodePoolNode(ctx, clusterID, nodeID) +} + +// GetLKECluster implements lkeclient.Client +func (_d ClientWithTracing) GetLKECluster(ctx context.Context, clusterID int) (lp1 *linodego.LKECluster, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.GetLKECluster") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID}, map[string]interface{}{ + "lp1": lp1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.GetLKECluster(ctx, clusterID) +} + +// GetLKEClusterDashboard implements lkeclient.Client +func (_d ClientWithTracing) GetLKEClusterDashboard(ctx context.Context, clusterID int) (lp1 *linodego.LKEClusterDashboard, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.GetLKEClusterDashboard") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID}, map[string]interface{}{ + "lp1": lp1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.GetLKEClusterDashboard(ctx, clusterID) +} + +// GetLKEClusterKubeconfig implements lkeclient.Client +func (_d ClientWithTracing) GetLKEClusterKubeconfig(ctx context.Context, clusterID int) (lp1 *linodego.LKEClusterKubeconfig, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.GetLKEClusterKubeconfig") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID}, map[string]interface{}{ + "lp1": lp1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.GetLKEClusterKubeconfig(ctx, clusterID) +} + +// ListLKEClusterAPIEndpoints implements lkeclient.Client +func (_d ClientWithTracing) ListLKEClusterAPIEndpoints(ctx context.Context, clusterID int, opts *linodego.ListOptions) (la1 []linodego.LKEClusterAPIEndpoint, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.ListLKEClusterAPIEndpoints") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID, + "opts": opts}, map[string]interface{}{ + "la1": la1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.ListLKEClusterAPIEndpoints(ctx, clusterID, opts) +} + +// ListLKENodePools implements lkeclient.Client +func (_d ClientWithTracing) ListLKENodePools(ctx context.Context, clusterID int, opts *linodego.ListOptions) (la1 []linodego.LKENodePool, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.ListLKENodePools") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID, + "opts": opts}, map[string]interface{}{ + "la1": la1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.ListLKENodePools(ctx, clusterID, opts) +} + +// ListLKEVersions implements lkeclient.Client +func (_d ClientWithTracing) ListLKEVersions(ctx context.Context, opts *linodego.ListOptions) (la1 []linodego.LKEVersion, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.ListLKEVersions") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "opts": opts}, map[string]interface{}{ + "la1": la1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.ListLKEVersions(ctx, opts) +} + +// UpdateLKECluster implements lkeclient.Client +func (_d ClientWithTracing) UpdateLKECluster(ctx context.Context, clusterID int, opts linodego.LKEClusterUpdateOptions) (lp1 *linodego.LKECluster, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.UpdateLKECluster") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID, + "opts": opts}, map[string]interface{}{ + "lp1": lp1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.UpdateLKECluster(ctx, clusterID, opts) +} + +// UpdateLKENodePool implements lkeclient.Client +func (_d ClientWithTracing) UpdateLKENodePool(ctx context.Context, clusterID int, poolID int, opts linodego.LKENodePoolUpdateOptions) (lp1 *linodego.LKENodePool, err error) { + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "lkeclient.Client.UpdateLKENodePool") + defer func() { + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "clusterID": clusterID, + "poolID": poolID, + "opts": opts}, map[string]interface{}{ + "lp1": lp1, + "err": err}) + } else if err != nil { + _span.RecordError(err) + _span.SetAttributes( + attribute.String("event", "error"), + attribute.String("message", err.Error()), + ) + } + + _span.End() + }() + return _d.Client.UpdateLKENodePool(ctx, clusterID, poolID, opts) +} diff --git a/internal/version/version.go b/internal/version/version.go index 9648d43..74fb99b 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -1,5 +1,5 @@ /* -Copyright 2024 anza-labs contributors. +Copyright 2024 lke-operator contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,4 +16,10 @@ limitations under the License. package version -var Version string +import "runtime" + +var ( + Version string + OS string = runtime.GOOS + Arch string = runtime.GOARCH +) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..a4b283d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,69 @@ +site_name: lke-operator +repo_url: https://github.com/anza-labs/lke-operator + +copyright: >- + Copyright © + <script> + document.write(new Date().getFullYear()) + </script> + lke-operator contributors + +plugins: +- search +- mkdocs-nav-weight + +markdown_extensions: +- admonition +- attr_list +- footnotes +- md_in_html +- pymdownx.details +- pymdownx.inlinehilite +- pymdownx.snippets +- pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true +- tables + +theme: + name: material + language: en + logo: assets/logo.png + favicon: assets/logo.png + + custom_dir: docs/overrides + + features: + - navigation.tabs + - header.autohide + - search.suggest + - search.highlight + + palette: + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + primary: blue grey + toggle: + icon: material/weather-sunny + name: Switch to dark mode + + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: blue grey + toggle: + icon: material/weather-night + name: Switch to light mode + +extra: + version: + provider: mike + consent: + title: Cookie consent + description: >- + We use cookies to recognize your repeated visits and preferences, as well + as to measure the effectiveness of our documentation and whether users + find what they're searching for. With your consent, you're helping us to + make our documentation better. diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..f8ed4c2 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,980 @@ +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. + +[[package]] +name = "babel" +version = "2.15.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, +] + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "black" +version = "24.4.2" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, + {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, + {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, + {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, + {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, + {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, + {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, + {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, + {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, + {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, + {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, + {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, + {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, + {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, + {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, + {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, + {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, + {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, + {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, + {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, + {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, + {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2024.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +description = "Copy your docs directly to the gh-pages branch." +optional = false +python-versions = "*" +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["flake8", "markdown", "twine", "wheel"] + +[[package]] +name = "idna" +version = "3.7" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "importlib-metadata" +version = "7.1.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "importlib-resources" +version = "6.4.0" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] + +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markdown" +version = "3.6" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"}, + {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"}, +] + +[package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +optional = false +python-versions = ">=3.6" +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mike" +version = "2.1.1" +description = "Manage multiple versions of your MkDocs-powered documentation" +optional = false +python-versions = "*" +files = [ + {file = "mike-2.1.1-py3-none-any.whl", hash = "sha256:0b1d01a397a423284593eeb1b5f3194e37169488f929b860c9bfe95c0d5efb79"}, + {file = "mike-2.1.1.tar.gz", hash = "sha256:f39ed39f3737da83ad0adc33e9f885092ed27f8c9e7ff0523add0480352a2c22"}, +] + +[package.dependencies] +importlib-metadata = "*" +importlib-resources = "*" +jinja2 = ">=2.7" +mkdocs = ">=1.0" +pyparsing = ">=3.0" +pyyaml = ">=5.1" +pyyaml-env-tag = "*" +verspec = "*" + +[package.extras] +dev = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] +test = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] + +[[package]] +name = "mkdocs" +version = "1.6.0" +description = "Project documentation with Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"}, + {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} +ghp-import = ">=1.0" +jinja2 = ">=2.11.1" +markdown = ">=3.3.6" +markupsafe = ">=2.0.1" +mergedeep = ">=1.3.4" +mkdocs-get-deps = ">=0.2.0" +packaging = ">=20.5" +pathspec = ">=0.11.1" +pyyaml = ">=5.1" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, + {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, +] + +[package.dependencies] +mergedeep = ">=1.3.4" +platformdirs = ">=2.2.0" +pyyaml = ">=5.1" + +[[package]] +name = "mkdocs-material" +version = "9.5.22" +description = "Documentation that simply works" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material-9.5.22-py3-none-any.whl", hash = "sha256:8c7a377d323567934e6cd46915e64dc209efceaec0dec1cf2202184f5649862c"}, + {file = "mkdocs_material-9.5.22.tar.gz", hash = "sha256:22a853a456ae8c581c4628159574d6fc7c71b2c7569dc9c3a82cc70432219599"}, +] + +[package.dependencies] +babel = ">=2.10,<3.0" +colorama = ">=0.4,<1.0" +jinja2 = ">=3.0,<4.0" +markdown = ">=3.2,<4.0" +mkdocs = ">=1.6,<2.0" +mkdocs-material-extensions = ">=1.3,<2.0" +paginate = ">=0.5,<1.0" +pygments = ">=2.16,<3.0" +pymdown-extensions = ">=10.2,<11.0" +regex = ">=2022.4" +requests = ">=2.26,<3.0" + +[package.extras] +git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"] +imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"] +recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +description = "Extension pack for Python Markdown and MkDocs Material." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, + {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, +] + +[[package]] +name = "mkdocs-nav-weight" +version = "0.2.0" +description = "A simple mkdocs plugin, enables to organize Navigation in a more markdownic way." +optional = false +python-versions = "*" +files = [ + {file = "mkdocs-nav-weight-0.2.0.tar.gz", hash = "sha256:3a9531209fabb08ee7d18fa491cc5556d05f09631ff837c3b8d076f277e9b54b"}, + {file = "mkdocs_nav_weight-0.2.0-py3-none-any.whl", hash = "sha256:a6ed14bb57c6679f52ce8516e6576a5dbdf1a644e0725870d9ab4977d23270c3"}, +] + +[package.dependencies] +mkdocs = ">=1" + +[[package]] +name = "mypy" +version = "1.10.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, + {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, + {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, + {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, + {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, + {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, + {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, + {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, + {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, + {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, + {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, + {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, + {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, + {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, + {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, + {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, + {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, + {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "24.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "paginate" +version = "0.5.6" +description = "Divides large result sets into pages for easier browsing" +optional = false +python-versions = "*" +files = [ + {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, + {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pymdown-extensions" +version = "10.8.1" +description = "Extension pack for Python Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb"}, + {file = "pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940"}, +] + +[package.dependencies] +markdown = ">=3.6" +pyyaml = "*" + +[package.extras] +extra = ["pygments (>=2.12)"] + +[[package]] +name = "pyparsing" +version = "3.1.2" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "regex" +version = "2024.5.10" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.8" +files = [ + {file = "regex-2024.5.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:eda3dd46df535da787ffb9036b5140f941ecb91701717df91c9daf64cabef953"}, + {file = "regex-2024.5.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d5bd666466c8f00a06886ce1397ba8b12371c1f1c6d1bef11013e9e0a1464a8"}, + {file = "regex-2024.5.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:32e5f3b8e32918bfbdd12eca62e49ab3031125c454b507127ad6ecbd86e62fca"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:534efd2653ebc4f26fc0e47234e53bf0cb4715bb61f98c64d2774a278b58c846"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:193b7c6834a06f722f0ce1ba685efe80881de7c3de31415513862f601097648c"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:160ba087232c5c6e2a1e7ad08bd3a3f49b58c815be0504d8c8aacfb064491cd8"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:951be1eae7b47660412dc4938777a975ebc41936d64e28081bf2e584b47ec246"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8a0f0ab5453e409586b11ebe91c672040bc804ca98d03a656825f7890cbdf88"}, + {file = "regex-2024.5.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9e6d4d6ae1827b2f8c7200aaf7501c37cf3f3896c86a6aaf2566448397c823dd"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:161a206c8f3511e2f5fafc9142a2cc25d7fe9a1ec5ad9b4ad2496a7c33e1c5d2"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:44b3267cea873684af022822195298501568ed44d542f9a2d9bebc0212e99069"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:560278c9975694e1f0bc50da187abf2cdc1e4890739ea33df2bc4a85eeef143e"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:70364a097437dd0a90b31cd77f09f7387ad9ac60ef57590971f43b7fca3082a5"}, + {file = "regex-2024.5.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:42be5de7cc8c1edac55db92d82b68dc8e683b204d6f5414c5a51997a323d7081"}, + {file = "regex-2024.5.10-cp310-cp310-win32.whl", hash = "sha256:9a8625849387b9d558d528e263ecc9c0fbde86cfa5c2f0eef43fff480ae24d71"}, + {file = "regex-2024.5.10-cp310-cp310-win_amd64.whl", hash = "sha256:903350bf44d7e4116b4d5898b30b15755d61dcd3161e3413a49c7db76f0bee5a"}, + {file = "regex-2024.5.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bf9596cba92ce7b1fd32c7b07c6e3212c7eed0edc271757e48bfcd2b54646452"}, + {file = "regex-2024.5.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:45cc13d398b6359a7708986386f72bd156ae781c3e83a68a6d4cee5af04b1ce9"}, + {file = "regex-2024.5.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ad45f3bccfcb00868f2871dce02a755529838d2b86163ab8a246115e80cfb7d6"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33d19f0cde6838c81acffff25c7708e4adc7dd02896c9ec25c3939b1500a1778"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a9f89d7db5ef6bdf53e5cc8e6199a493d0f1374b3171796b464a74ebe8e508a"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c6c71cf92b09e5faa72ea2c68aa1f61c9ce11cb66fdc5069d712f4392ddfd00"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7467ad8b0eac0b28e52679e972b9b234b3de0ea5cee12eb50091d2b68145fe36"}, + {file = "regex-2024.5.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc0db93ad039fc2fe32ccd3dd0e0e70c4f3d6e37ae83f0a487e1aba939bd2fbd"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fa9335674d7c819674467c7b46154196c51efbaf5f5715187fd366814ba3fa39"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7dda3091838206969c2b286f9832dff41e2da545b99d1cfaea9ebd8584d02708"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:504b5116e2bd1821efd815941edff7535e93372a098e156bb9dffde30264e798"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:91b53dea84415e8115506cc62e441a2b54537359c63d856d73cb1abe05af4c9a"}, + {file = "regex-2024.5.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a3903128f9e17a500618e80c68165c78c741ebb17dd1a0b44575f92c3c68b02"}, + {file = "regex-2024.5.10-cp311-cp311-win32.whl", hash = "sha256:236cace6c1903effd647ed46ce6dd5d76d54985fc36dafc5256032886736c85d"}, + {file = "regex-2024.5.10-cp311-cp311-win_amd64.whl", hash = "sha256:12446827f43c7881decf2c126762e11425de5eb93b3b0d8b581344c16db7047a"}, + {file = "regex-2024.5.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:14905ed75c7a6edf423eb46c213ed3f4507c38115f1ed3c00f4ec9eafba50e58"}, + {file = "regex-2024.5.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4fad420b14ae1970a1f322e8ae84a1d9d89375eb71e1b504060ab2d1bfe68f3c"}, + {file = "regex-2024.5.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c46a76a599fcbf95f98755275c5527304cc4f1bb69919434c1e15544d7052910"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0faecb6d5779753a6066a3c7a0471a8d29fe25d9981ca9e552d6d1b8f8b6a594"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aab65121229c2ecdf4a31b793d99a6a0501225bd39b616e653c87b219ed34a49"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50e7e96a527488334379e05755b210b7da4a60fc5d6481938c1fa053e0c92184"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba034c8db4b264ef1601eb33cd23d87c5013b8fb48b8161debe2e5d3bd9156b0"}, + {file = "regex-2024.5.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:031219782d97550c2098d9a68ce9e9eaefe67d2d81d8ff84c8354f9c009e720c"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:62b5f7910b639f3c1d122d408421317c351e213ca39c964ad4121f27916631c6"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cd832bd9b6120d6074f39bdfbb3c80e416848b07ac72910f1c7f03131a6debc3"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:e91b1976358e17197157b405cab408a5f4e33310cda211c49fc6da7cffd0b2f0"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:571452362d552de508c37191b6abbbb660028b8b418e2d68c20779e0bc8eaaa8"}, + {file = "regex-2024.5.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5253dcb0bfda7214523de58b002eb0090cb530d7c55993ce5f6d17faf953ece7"}, + {file = "regex-2024.5.10-cp312-cp312-win32.whl", hash = "sha256:2f30a5ab8902f93930dc6f627c4dd5da2703333287081c85cace0fc6e21c25af"}, + {file = "regex-2024.5.10-cp312-cp312-win_amd64.whl", hash = "sha256:3799e36d60a35162bb35b2246d8bb012192b7437dff807ef79c14e7352706306"}, + {file = "regex-2024.5.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bbdc5db2c98ac2bf1971ffa1410c87ca7a15800415f788971e8ba8520fc0fda9"}, + {file = "regex-2024.5.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6ccdeef4584450b6f0bddd5135354908dacad95425fcb629fe36d13e48b60f32"}, + {file = "regex-2024.5.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:29d839829209f3c53f004e1de8c3113efce6d98029f044fa5cfee666253ee7e6"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0709ba544cf50bd5cb843df4b8bb6701bae2b70a8e88da9add8386cbca5c1385"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:972b49f2fe1047b9249c958ec4fa1bdd2cf8ce305dc19d27546d5a38e57732d8"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cdbb1998da94607d5eec02566b9586f0e70d6438abf1b690261aac0edda7ab6"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7c8ee4861d9ef5b1120abb75846828c811f932d63311596ad25fa168053e00"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d35d4cc9270944e95f9c88af757b0c9fc43f396917e143a5756608462c5223b"}, + {file = "regex-2024.5.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8722f72068b3e1156a4b2e1afde6810f1fc67155a9fa30a4b9d5b4bc46f18fb0"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:696639a73ca78a380acfaa0a1f6dd8220616a99074c05bba9ba8bb916914b224"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea057306ab469130167014b662643cfaed84651c792948891d003cf0039223a5"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b43b78f9386d3d932a6ce5af4b45f393d2e93693ee18dc4800d30a8909df700e"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c43395a3b7cc9862801a65c6994678484f186ce13c929abab44fb8a9e473a55a"}, + {file = "regex-2024.5.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0bc94873ba11e34837bffd7e5006703abeffc4514e2f482022f46ce05bd25e67"}, + {file = "regex-2024.5.10-cp38-cp38-win32.whl", hash = "sha256:1118ba9def608250250f4b3e3f48c62f4562ba16ca58ede491b6e7554bfa09ff"}, + {file = "regex-2024.5.10-cp38-cp38-win_amd64.whl", hash = "sha256:458d68d34fb74b906709735c927c029e62f7d06437a98af1b5b6258025223210"}, + {file = "regex-2024.5.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:15e593386ec6331e0ab4ac0795b7593f02ab2f4b30a698beb89fbdc34f92386a"}, + {file = "regex-2024.5.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ca23b41355ba95929e9505ee04e55495726aa2282003ed9b012d86f857d3e49b"}, + {file = "regex-2024.5.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c8982ee19ccecabbaeac1ba687bfef085a6352a8c64f821ce2f43e6d76a9298"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7117cb7d6ac7f2e985f3d18aa8a1728864097da1a677ffa69e970ca215baebf1"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b66421f8878a0c82fc0c272a43e2121c8d4c67cb37429b764f0d5ad70b82993b"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:224a9269f133564109ce668213ef3cb32bc72ccf040b0b51c72a50e569e9dc9e"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab98016541543692a37905871a5ffca59b16e08aacc3d7d10a27297b443f572d"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51d27844763c273a122e08a3e86e7aefa54ee09fb672d96a645ece0454d8425e"}, + {file = "regex-2024.5.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:853cc36e756ff673bf984e9044ccc8fad60b95a748915dddeab9488aea974c73"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4e7eaf9df15423d07b6050fb91f86c66307171b95ea53e2d87a7993b6d02c7f7"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:169fd0acd7a259f58f417e492e93d0e15fc87592cd1e971c8c533ad5703b5830"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:334b79ce9c08f26b4659a53f42892793948a613c46f1b583e985fd5a6bf1c149"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f03b1dbd4d9596dd84955bb40f7d885204d6aac0d56a919bb1e0ff2fb7e1735a"}, + {file = "regex-2024.5.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfa6d61a76c77610ba9274c1a90a453062bdf6887858afbe214d18ad41cf6bde"}, + {file = "regex-2024.5.10-cp39-cp39-win32.whl", hash = "sha256:249fbcee0a277c32a3ce36d8e36d50c27c968fdf969e0fbe342658d4e010fbc8"}, + {file = "regex-2024.5.10-cp39-cp39-win_amd64.whl", hash = "sha256:0ce56a923f4c01d7568811bfdffe156268c0a7aae8a94c902b92fe34c4bde785"}, + {file = "regex-2024.5.10.tar.gz", hash = "sha256:304e7e2418146ae4d0ef0e9ffa28f881f7874b45b4994cc2279b21b6e7ae50c8"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "semver" +version = "3.0.2" +description = "Python helper for Semantic Versioning (https://semver.org)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4"}, + {file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "typing-extensions" +version = "4.11.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, +] + +[[package]] +name = "urllib3" +version = "2.2.1" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "verspec" +version = "0.1.0" +description = "Flexible version handling" +optional = false +python-versions = "*" +files = [ + {file = "verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31"}, + {file = "verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e"}, +] + +[package.extras] +test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] + +[[package]] +name = "watchdog" +version = "4.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, + {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, + {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, + {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, + {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, + {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, + {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, + {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[[package]] +name = "zipp" +version = "3.18.1" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.12" +content-hash = "6af32f9005d51a1340af75a0815fd1c0154f5bc9b1451e88a1d178fece932e81" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ddae01a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,31 @@ +[tool.poetry] +name = "docs" +authors = [] +description = "Documentation for lke-operator" +version = "0.1.0" + +[tool.poetry.dependencies] +python = "^3.12" +mike = "^2.0.0" +mkdocs = "^1.5.3" +mkdocs-material = "^9.5.15" +semver = "^3.0.2" +mkdocs-nav-weight = "^0.2.0" + +[tool.poetry.scripts] +publish = 'hack.publish:run' + +[tool.poetry.group.dev.dependencies] +black = "^24.3.0" +mypy = "^1.9.0" +isort = "^5.13.2" + +[tool.mypy] +disable_error_code = "import-untyped" + +[tool.isort] +profile = "black" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/test/base/apply.yaml b/test/base/apply.yaml index e69de29..c3af6fb 100644 --- a/test/base/apply.yaml +++ b/test/base/apply.yaml @@ -0,0 +1,12 @@ +apiVersion: lke.anza-labs.dev/v1alpha1 +kind: LKEClusterConfig +metadata: + name: base +spec: + tokenSecretRef: + name: test-token + namespace: test-shared + region: eu-central + nodePools: + - nodeCount: 3 + linodeType: g6-standard-1 diff --git a/test/base/assert.yaml b/test/base/assert.yaml index e69de29..c7ed90b 100644 --- a/test/base/assert.yaml +++ b/test/base/assert.yaml @@ -0,0 +1,14 @@ +apiVersion: lke.anza-labs.dev/v1alpha1 +kind: LKEClusterConfig +metadata: + name: base +spec: + tokenSecretRef: + name: test-token + namespace: test-shared + region: eu-central + nodePools: + - nodeCount: 3 + linodeType: g6-standard-1 +status: + phase: Active