mirror of
https://github.com/outbackdingo/proxmox-cloud-controller-manager.git
synced 2026-01-27 02:20:02 +00:00
feat: add controllers
Add cloud-node, cloud-node-lifecycle controllers.
This commit is contained in:
@@ -2,7 +2,10 @@
|
|||||||
.github/
|
.github/
|
||||||
.git/
|
.git/
|
||||||
**/.gitignore
|
**/.gitignore
|
||||||
|
#
|
||||||
charts/
|
charts/
|
||||||
|
docs/
|
||||||
|
hack/
|
||||||
Dockerfile
|
Dockerfile
|
||||||
/proxmox-cloud-controller-manager*
|
/proxmox-cloud-controller-manager*
|
||||||
#
|
#
|
||||||
|
|||||||
11
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
11
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: Feature Requests
|
||||||
|
about: Create a feature request.
|
||||||
|
title: ""
|
||||||
|
labels: ""
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
## Feature Request
|
||||||
|
|
||||||
|
### Description
|
||||||
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Pull Request
|
||||||
|
|
||||||
|
<!--
|
||||||
|
## Note to the Contributor
|
||||||
|
|
||||||
|
We encourage contributors to go through a proposal process to discuss major changes.
|
||||||
|
Before your PR is allowed to run through CI, the maintainers of Talos CCM will first have to approve the PR.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## What? (description)
|
||||||
|
|
||||||
|
## Why? (reasoning)
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
|
||||||
|
Please use the following checklist:
|
||||||
|
|
||||||
|
- [ ] you linked an issue (if applicable)
|
||||||
|
- [ ] you included tests (if applicable)
|
||||||
|
- [ ] you linted your code (`make lint`)
|
||||||
|
- [ ] you linted your code (`make unit`)
|
||||||
|
|
||||||
|
> See `make help` for a description of the available targets.
|
||||||
29
.github/dependabot.yml
vendored
Normal file
29
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
# See https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "gomod"
|
||||||
|
directory: "/"
|
||||||
|
commit-message:
|
||||||
|
prefix: "chore:"
|
||||||
|
open-pull-requests-limit: 5
|
||||||
|
rebase-strategy: disabled
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
time: "07:00"
|
||||||
|
timezone: "UTC"
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "/"
|
||||||
|
commit-message:
|
||||||
|
prefix: "chore:"
|
||||||
|
open-pull-requests-limit: 5
|
||||||
|
rebase-strategy: disabled
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
time: "07:00"
|
||||||
|
timezone: "UTC"
|
||||||
37
.github/workflows/build-edge.yaml
vendored
Normal file
37
.github/workflows/build-edge.yaml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: Build edge
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'go.mod'
|
||||||
|
- 'go.sum'
|
||||||
|
- 'cmd/**'
|
||||||
|
- 'pkg/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-publish:
|
||||||
|
name: "Build image and publish"
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up docker buildx
|
||||||
|
run: make docker-init
|
||||||
|
- name: Github registry login
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
run: make images
|
||||||
|
env:
|
||||||
|
PUSH: "true"
|
||||||
|
TAG: "edge"
|
||||||
34
.github/workflows/build-test.yaml
vendored
Normal file
34
.github/workflows/build-test.yaml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Build check
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'go.mod'
|
||||||
|
- 'go.sum'
|
||||||
|
- 'cmd/**'
|
||||||
|
- 'pkg/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up go
|
||||||
|
uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version-file: 'go.mod'
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: make build
|
||||||
|
- name: Lint
|
||||||
|
uses: golangci/golangci-lint-action@v3
|
||||||
|
with:
|
||||||
|
args: --config=.golangci.yml
|
||||||
29
.github/workflows/charts.yaml
vendored
Normal file
29
.github/workflows/charts.yaml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
name: Helm chart check
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'charts/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
helm-lint:
|
||||||
|
name: Helm chart check
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Unshallow
|
||||||
|
run: git fetch --prune --unshallow
|
||||||
|
|
||||||
|
- name: Install chart-testing tools
|
||||||
|
id: lint
|
||||||
|
uses: helm/chart-testing-action@v2.3.1
|
||||||
|
|
||||||
|
- name: Run helm chart linter
|
||||||
|
run: ct --config hack/ct.yml lint
|
||||||
|
- name: Run helm template
|
||||||
|
run: |
|
||||||
|
helm template -n kube-system -f charts/talos-cloud-controller-manager/values-tests.yaml \
|
||||||
|
ccm charts/talos-cloud-controller-manager > /dev/null
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,6 @@
|
|||||||
#
|
#
|
||||||
|
/charts/proxmox-cloud-controller-manager/values-dev.yaml
|
||||||
/proxmox-cloud-controller-manager*
|
/proxmox-cloud-controller-manager*
|
||||||
/kubeconfig
|
/kubeconfig
|
||||||
|
/proxmox-config.yaml
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -124,8 +124,7 @@ linters-settings:
|
|||||||
max-complexity: 20
|
max-complexity: 20
|
||||||
gomoddirectives:
|
gomoddirectives:
|
||||||
replace-local: true
|
replace-local: true
|
||||||
replace-allow-list:
|
replace-allow-list: []
|
||||||
- cloud.google.com/go
|
|
||||||
retract-allow-no-explanation: false
|
retract-allow-no-explanation: false
|
||||||
exclude-forbidden: true
|
exclude-forbidden: true
|
||||||
|
|
||||||
|
|||||||
24
Dockerfile
Normal file
24
Dockerfile
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# syntax = docker/dockerfile:1.4
|
||||||
|
########################################
|
||||||
|
|
||||||
|
FROM --platform=${BUILDPLATFORM} golang:1.20.3-alpine3.17 AS builder
|
||||||
|
RUN apk update && apk add --no-cache make
|
||||||
|
ENV GO111MODULE on
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
COPY go.mod go.sum /src
|
||||||
|
RUN go mod download && go mod verify
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
ARG TAG
|
||||||
|
RUN make build-all-archs
|
||||||
|
|
||||||
|
########################################
|
||||||
|
|
||||||
|
FROM --platform=${TARGETARCH} gcr.io/distroless/static-debian11:nonroot AS release
|
||||||
|
LABEL org.opencontainers.image.source https://github.com/sergelogvinov/proxmox-cloud-controller-manager
|
||||||
|
|
||||||
|
ARG TARGETARCH
|
||||||
|
COPY --from=builder /src/proxmox-cloud-controller-manager-${TARGETARCH} /proxmox-cloud-controller-manager
|
||||||
|
|
||||||
|
ENTRYPOINT ["/proxmox-cloud-controller-manager"]
|
||||||
30
Makefile
30
Makefile
@@ -32,7 +32,7 @@ To build this project, you must have the following installed:
|
|||||||
|
|
||||||
- git
|
- git
|
||||||
- make
|
- make
|
||||||
- golang 1.19
|
- golang 1.20+
|
||||||
- golangci-lint
|
- golangci-lint
|
||||||
|
|
||||||
endef
|
endef
|
||||||
@@ -45,6 +45,9 @@ help: ## This help menu.
|
|||||||
|
|
||||||
# Build Abstractions
|
# Build Abstractions
|
||||||
|
|
||||||
|
build-all-archs:
|
||||||
|
@for arch in $(ARCHS); do $(MAKE) ARCH=$${arch} build ; done
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: ## Build
|
build: ## Build
|
||||||
CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build $(GO_LDFLAGS) \
|
CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build $(GO_LDFLAGS) \
|
||||||
@@ -52,7 +55,7 @@ build: ## Build
|
|||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run: build
|
run: build
|
||||||
./proxmox-cloud-controller-manager-$(ARCH) --v=4 --kubeconfig=kubeconfig --cloud-config=hack/proxmox-config.yaml --controllers=cloud-node \
|
./proxmox-cloud-controller-manager-$(ARCH) --v=5 --kubeconfig=kubeconfig --cloud-config=proxmox-config.yaml --controllers=cloud-node,cloud-node-lifecycle \
|
||||||
--use-service-account-credentials --leader-elect=false --bind-address=127.0.0.1
|
--use-service-account-credentials --leader-elect=false --bind-address=127.0.0.1
|
||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
@@ -62,3 +65,26 @@ lint: ## Lint
|
|||||||
.PHONY: unit
|
.PHONY: unit
|
||||||
unit:
|
unit:
|
||||||
go test -tags=unit $(shell go list ./...) $(TESTARGS)
|
go test -tags=unit $(shell go list ./...) $(TESTARGS)
|
||||||
|
|
||||||
|
.PHONY: docs
|
||||||
|
docs:
|
||||||
|
helm template -n kube-system proxmox-cloud-controller-manager \
|
||||||
|
--set-string image.tag=$(TAG) \
|
||||||
|
charts/proxmox-cloud-controller-manager > docs/deploy/cloud-controller-manager.yml
|
||||||
|
|
||||||
|
# Docker stages
|
||||||
|
|
||||||
|
docker-init:
|
||||||
|
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||||
|
|
||||||
|
docker context create multiarch ||:
|
||||||
|
docker buildx create --name multiarch --driver docker-container --use ||:
|
||||||
|
docker context use multiarch
|
||||||
|
docker buildx inspect --bootstrap multiarch
|
||||||
|
|
||||||
|
.PHONY: images
|
||||||
|
images:
|
||||||
|
@docker buildx build $(BUILD_ARGS) \
|
||||||
|
--build-arg TAG=$(TAG) \
|
||||||
|
-t $(IMAGE):$(TAG) \
|
||||||
|
-f Dockerfile .
|
||||||
|
|||||||
57
README.md
57
README.md
@@ -1,2 +1,55 @@
|
|||||||
# proxmox-cloud-controller-manager
|
# Proxmox Cloud Controller Manager
|
||||||
Proxmox CCM
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# cloud provider config
|
||||||
|
clusters:
|
||||||
|
- url: https://cluster-api-1.exmple.com:8006/api2/json
|
||||||
|
insecure: false
|
||||||
|
token_id: "user!token-id"
|
||||||
|
token_secret: "secret"
|
||||||
|
region: cluster-1
|
||||||
|
- url: https://cluster-api-2.exmple.com:8006/api2/json
|
||||||
|
insecure: false
|
||||||
|
token_id: "user!token-id"
|
||||||
|
token_secret: "secret"
|
||||||
|
region: cluster-2
|
||||||
|
```
|
||||||
|
|
||||||
|
Node spec result:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Node
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
...
|
||||||
|
node.kubernetes.io/instance-type: 2VCPU-2GB
|
||||||
|
topology.kubernetes.io/region: cluster-1
|
||||||
|
topology.kubernetes.io/zone: pve-node-1
|
||||||
|
name: worker-1
|
||||||
|
spec:
|
||||||
|
...
|
||||||
|
providerID: proxmox://cluster-1/123
|
||||||
|
status:
|
||||||
|
addresses:
|
||||||
|
- address: 172.16.0.31
|
||||||
|
type: InternalIP
|
||||||
|
- address: worker-1
|
||||||
|
type: Hostname
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
### kubectl
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl apply -f https://raw.githubusercontent.com/sergelogvinov/proxmox-cloud-controller-manager/main/docs/deploy/cloud-controller-manager.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Helm install
|
||||||
|
|
||||||
|
```shell
|
||||||
|
helm upgrade -i --namespace=kube-system proxmox-cloud-controller-manager charts/proxmox-cloud-controller-manager
|
||||||
|
```
|
||||||
|
|||||||
23
charts/proxmox-cloud-controller-manager/.helmignore
Normal file
23
charts/proxmox-cloud-controller-manager/.helmignore
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*.orig
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
||||||
|
.vscode/
|
||||||
15
charts/proxmox-cloud-controller-manager/Chart.yaml
Normal file
15
charts/proxmox-cloud-controller-manager/Chart.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: proxmox-cloud-controller-manager
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
type: application
|
||||||
|
|
||||||
|
# This is the chart version. This version number should be incremented each time you make changes
|
||||||
|
# to the chart and its templates, including the app version.
|
||||||
|
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||||
|
version: 0.1.0
|
||||||
|
|
||||||
|
# This is the version number of the application being deployed. This version number should be
|
||||||
|
# incremented each time you make changes to the application. Versions are not expected to
|
||||||
|
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||||
|
# It is recommended to use it with quotes.
|
||||||
|
appVersion: "0.0.1"
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "proxmox-cloud-controller-manager.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "proxmox-cloud-controller-manager.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "proxmox-cloud-controller-manager.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "proxmox-cloud-controller-manager.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "proxmox-cloud-controller-manager.chart" . }}
|
||||||
|
{{ include "proxmox-cloud-controller-manager.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "proxmox-cloud-controller-manager.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "proxmox-cloud-controller-manager.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "proxmox-cloud-controller-manager.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "proxmox-cloud-controller-manager.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Generate string of enabled controllers. Might have a trailing comma (,) which needs to be trimmed.
|
||||||
|
*/}}
|
||||||
|
{{- define "proxmox-cloud-controller-manager.enabledControllers" }}
|
||||||
|
{{- range .Values.enabledControllers -}}{{ . }},{{- end -}}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "proxmox-cloud-controller-manager.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "proxmox-cloud-controller-manager.labels" . | nindent 4 }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
strategy:
|
||||||
|
type: {{ .Values.updateStrategy.type }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "proxmox-cloud-controller-manager.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "proxmox-cloud-controller-manager.selectorLabels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "proxmox-cloud-controller-manager.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
command: ["/proxmox-cloud-controller-manager"]
|
||||||
|
args:
|
||||||
|
- --v={{ .Values.logVerbosityLevel }}
|
||||||
|
- --cloud-provider=proxmox
|
||||||
|
- --cloud-config=/etc/proxmox/config.yaml
|
||||||
|
- --controllers={{- trimAll "," (include "proxmox-cloud-controller-manager.enabledControllers" . ) }}
|
||||||
|
- --leader-elect-resource-name=cloud-controller-manager-proxmox
|
||||||
|
- --use-service-account-credentials
|
||||||
|
- --secure-port=10258
|
||||||
|
{{- with .Values.extraArgs }}
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 10258
|
||||||
|
scheme: HTTPS
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 30
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: cloud-config
|
||||||
|
mountPath: /etc/proxmox
|
||||||
|
readOnly: true
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
volumes:
|
||||||
|
- name: cloud-config
|
||||||
|
secret:
|
||||||
|
secretName: {{ include "proxmox-cloud-controller-manager.fullname" . }}
|
||||||
|
defaultMode: 416 # 0640
|
||||||
53
charts/proxmox-cloud-controller-manager/templates/role.yaml
Normal file
53
charts/proxmox-cloud-controller-manager/templates/role.yaml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: system:{{ include "proxmox-cloud-controller-manager.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "proxmox-cloud-controller-manager.labels" . | nindent 4 }}
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- coordination.k8s.io
|
||||||
|
resources:
|
||||||
|
- leases
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- events
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- nodes
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- nodes/status
|
||||||
|
verbs:
|
||||||
|
- patch
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- serviceaccounts
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- get
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- serviceaccounts/token
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: system:{{ include "proxmox-cloud-controller-manager.fullname" . }}
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: system:{{ include "proxmox-cloud-controller-manager.fullname" . }}
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: {{ include "proxmox-cloud-controller-manager.fullname" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: system:{{ include "proxmox-cloud-controller-manager.fullname" . }}:extension-apiserver-authentication-reader
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: extension-apiserver-authentication-reader
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: {{ include "proxmox-cloud-controller-manager.fullname" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "proxmox-cloud-controller-manager.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "proxmox-cloud-controller-manager.labels" . | nindent 4 }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
data:
|
||||||
|
config.yaml: {{ toYaml .Values.config | b64enc | quote }}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "proxmox-cloud-controller-manager.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "proxmox-cloud-controller-manager.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/sergelogvinov/proxmox-cloud-controller-manager
|
||||||
|
pullPolicy: Always
|
||||||
|
tag: edge
|
||||||
|
|
||||||
|
logVerbosityLevel: 4
|
||||||
115
charts/proxmox-cloud-controller-manager/values.yaml
Normal file
115
charts/proxmox-cloud-controller-manager/values.yaml
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
# Default values for proxmox-cloud-controller-manager.
|
||||||
|
# This is a YAML-formatted file.
|
||||||
|
# Declare variables to be passed into your templates.
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/sergelogvinov/proxmox-cloud-controller-manager
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
# Overrides the image tag whose default is the chart appVersion.
|
||||||
|
tag: ""
|
||||||
|
|
||||||
|
imagePullSecrets: []
|
||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
# -- Any extra arguments for talos-cloud-controller-manager
|
||||||
|
extraArgs: []
|
||||||
|
# - --cluster-name=kubernetes
|
||||||
|
|
||||||
|
# -- List of controllers should be enabled.
|
||||||
|
# Use '*' to enable all controllers.
|
||||||
|
# Support only `cloud-node,cloud-node-lifecycle` controllers.
|
||||||
|
enabledControllers:
|
||||||
|
- cloud-node
|
||||||
|
- cloud-node-lifecycle
|
||||||
|
# - route
|
||||||
|
# - service
|
||||||
|
|
||||||
|
# -- Log verbosity level. See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md
|
||||||
|
# for description of individual verbosity levels.
|
||||||
|
logVerbosityLevel: 2
|
||||||
|
|
||||||
|
config:
|
||||||
|
clusters: []
|
||||||
|
# - url: https://cluster-api-1.exmple.com:8006/api2/json
|
||||||
|
# insecure: false
|
||||||
|
# token_id: "login!name"
|
||||||
|
# token_secret: "secret"
|
||||||
|
# region: cluster-1
|
||||||
|
|
||||||
|
# -- Pods Service Account.
|
||||||
|
# ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
|
||||||
|
serviceAccount:
|
||||||
|
# Specifies whether a service account should be created
|
||||||
|
create: true
|
||||||
|
# Annotations to add to the service account
|
||||||
|
annotations: {}
|
||||||
|
# The name of the service account to use.
|
||||||
|
# If not set and create is true, a name is generated using the fullname template
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
# -- CCM pods' priorityClassName.
|
||||||
|
priorityClassName: system-cluster-critical
|
||||||
|
|
||||||
|
# -- Annotations for data pods.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||||
|
podAnnotations: {}
|
||||||
|
|
||||||
|
# -- Pods Security Context.
|
||||||
|
# ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
|
||||||
|
podSecurityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 10258
|
||||||
|
runAsGroup: 10258
|
||||||
|
fsGroup: 10258
|
||||||
|
fsGroupChangePolicy: "OnRootMismatch"
|
||||||
|
|
||||||
|
# -- Container Security Context.
|
||||||
|
# ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
|
||||||
|
resources:
|
||||||
|
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||||
|
# choice for the user. This also increases chances charts run on environments with little
|
||||||
|
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||||
|
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
|
||||||
|
# -- Deployment update stategy type.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#updating-a-deployment
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
|
||||||
|
# -- Node labels for data pods assignment.
|
||||||
|
# ref: https://kubernetes.io/docs/user-guide/node-selection/
|
||||||
|
nodeSelector: {}
|
||||||
|
# node-role.kubernetes.io/control-plane: ""
|
||||||
|
|
||||||
|
# -- Tolerations for data pods assignment.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
|
||||||
|
tolerations:
|
||||||
|
- effect: NoSchedule
|
||||||
|
key: node-role.kubernetes.io/control-plane
|
||||||
|
operator: Exists
|
||||||
|
- effect: NoSchedule
|
||||||
|
key: node.cloudprovider.kubernetes.io/uninitialized
|
||||||
|
operator: Exists
|
||||||
|
|
||||||
|
# -- Affinity for data pods assignment.
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
|
||||||
|
affinity: {}
|
||||||
198
docs/deploy/cloud-controller-manager.yml
Normal file
198
docs/deploy/cloud-controller-manager.yml
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
---
|
||||||
|
# Source: proxmox-cloud-controller-manager/templates/serviceaccount.yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: proxmox-cloud-controller-manager
|
||||||
|
labels:
|
||||||
|
helm.sh/chart: proxmox-cloud-controller-manager-0.1.0
|
||||||
|
app.kubernetes.io/name: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/instance: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/version: "0.0.1"
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
# Source: proxmox-cloud-controller-manager/templates/secrets.yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: proxmox-cloud-controller-manager
|
||||||
|
labels:
|
||||||
|
helm.sh/chart: proxmox-cloud-controller-manager-0.1.0
|
||||||
|
app.kubernetes.io/name: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/instance: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/version: "0.0.1"
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
namespace: kube-system
|
||||||
|
data:
|
||||||
|
config.yaml: "Y2x1c3RlcnM6IFtd"
|
||||||
|
---
|
||||||
|
# Source: proxmox-cloud-controller-manager/templates/role.yaml
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: system:proxmox-cloud-controller-manager
|
||||||
|
labels:
|
||||||
|
helm.sh/chart: proxmox-cloud-controller-manager-0.1.0
|
||||||
|
app.kubernetes.io/name: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/instance: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/version: "0.0.1"
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- coordination.k8s.io
|
||||||
|
resources:
|
||||||
|
- leases
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- events
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- nodes
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- nodes/status
|
||||||
|
verbs:
|
||||||
|
- patch
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- serviceaccounts
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- get
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- serviceaccounts/token
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
---
|
||||||
|
# Source: proxmox-cloud-controller-manager/templates/rolebinding.yaml
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: system:proxmox-cloud-controller-manager
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: system:proxmox-cloud-controller-manager
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: proxmox-cloud-controller-manager
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
# Source: proxmox-cloud-controller-manager/templates/rolebinding.yaml
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: system:proxmox-cloud-controller-manager:extension-apiserver-authentication-reader
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: extension-apiserver-authentication-reader
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: proxmox-cloud-controller-manager
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
# Source: proxmox-cloud-controller-manager/templates/deployment.yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: proxmox-cloud-controller-manager
|
||||||
|
labels:
|
||||||
|
helm.sh/chart: proxmox-cloud-controller-manager-0.1.0
|
||||||
|
app.kubernetes.io/name: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/instance: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/version: "0.0.1"
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/instance: proxmox-cloud-controller-manager
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: proxmox-cloud-controller-manager
|
||||||
|
app.kubernetes.io/instance: proxmox-cloud-controller-manager
|
||||||
|
spec:
|
||||||
|
serviceAccountName: proxmox-cloud-controller-manager
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 10258
|
||||||
|
fsGroupChangePolicy: OnRootMismatch
|
||||||
|
runAsGroup: 10258
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 10258
|
||||||
|
containers:
|
||||||
|
- name: proxmox-cloud-controller-manager
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
image: "ghcr.io/sergelogvinov/proxmox-cloud-controller-manager:811670e"
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command: ["/proxmox-cloud-controller-manager"]
|
||||||
|
args:
|
||||||
|
- --v=2
|
||||||
|
- --cloud-provider=proxmox
|
||||||
|
- --cloud-config=/etc/proxmox/config.yaml
|
||||||
|
- --controllers=cloud-node,cloud-node-lifecycle
|
||||||
|
- --leader-elect-resource-name=cloud-controller-manager-proxmox
|
||||||
|
- --use-service-account-credentials
|
||||||
|
- --secure-port=10258
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 10258
|
||||||
|
scheme: HTTPS
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 30
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: cloud-config
|
||||||
|
mountPath: /etc/proxmox
|
||||||
|
readOnly: true
|
||||||
|
tolerations:
|
||||||
|
- effect: NoSchedule
|
||||||
|
key: node-role.kubernetes.io/control-plane
|
||||||
|
operator: Exists
|
||||||
|
- effect: NoSchedule
|
||||||
|
key: node.cloudprovider.kubernetes.io/uninitialized
|
||||||
|
operator: Exists
|
||||||
|
volumes:
|
||||||
|
- name: cloud-config
|
||||||
|
secret:
|
||||||
|
secretName: proxmox-cloud-controller-manager
|
||||||
|
defaultMode: 416 # 0640
|
||||||
1
go.mod
1
go.mod
@@ -3,6 +3,7 @@ module github.com/sergelogvinov/proxmox-cloud-controller-manager
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Telmate/proxmox-api-go v0.0.0-20230329163449-4d08b16c14e0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
k8s.io/api v0.26.3
|
k8s.io/api v0.26.3
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -42,6 +42,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
|||||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/Telmate/proxmox-api-go v0.0.0-20230329163449-4d08b16c14e0 h1:RpMkhkY8Vd1fT0CaNxWjw9XVBTmPAErYJfiPxnwFHaM=
|
||||||
|
github.com/Telmate/proxmox-api-go v0.0.0-20230329163449-4d08b16c14e0/go.mod h1:zQ/B1nkMv6ueUlAEr0D/x5eaFe3rHSScuTc08dcvvPI=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
clusters:
|
||||||
|
- url: https://cluster-api-1.exmple.com:8006/api2/json
|
||||||
|
insecure: false
|
||||||
|
token_id: "user!token-id"
|
||||||
|
token_secret: "secret"
|
||||||
|
region: cluster-1
|
||||||
|
- url: https://cluster-api-2.exmple.com:8006/api2/json
|
||||||
|
insecure: false
|
||||||
|
token_id: "user!token-id"
|
||||||
|
token_secret: "secret"
|
||||||
|
region: cluster-2
|
||||||
|
|||||||
@@ -1,18 +1,68 @@
|
|||||||
package proxmox
|
package proxmox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"crypto/tls"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
pxapi "github.com/Telmate/proxmox-api-go/proxmox"
|
||||||
|
|
||||||
clientkubernetes "k8s.io/client-go/kubernetes"
|
clientkubernetes "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
config *cloudConfig
|
config *cloudConfig
|
||||||
|
proxmox []pxCluster
|
||||||
kclient clientkubernetes.Interface
|
kclient clientkubernetes.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClient(ctx context.Context, config *cloudConfig) (*client, error) {
|
type pxCluster struct {
|
||||||
return &client{
|
client *pxapi.Client
|
||||||
config: config,
|
region string
|
||||||
}, nil
|
}
|
||||||
|
|
||||||
|
func newClient(config *cloudConfig) (*client, error) {
|
||||||
|
clusters := len(config.Clusters)
|
||||||
|
if clusters > 0 {
|
||||||
|
proxmox := make([]pxCluster, clusters)
|
||||||
|
|
||||||
|
for idx, cfg := range config.Clusters {
|
||||||
|
tlsconf := &tls.Config{InsecureSkipVerify: true}
|
||||||
|
if !cfg.Insecure {
|
||||||
|
tlsconf = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := pxapi.NewClient(cfg.URL, nil, os.Getenv("PM_HTTP_HEADERS"), tlsconf, "", 600)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client.SetAPIToken(cfg.TokenID, cfg.TokenSecret)
|
||||||
|
|
||||||
|
if _, err := client.GetVersion(); err != nil {
|
||||||
|
klog.Errorf("failed to initialized proxmox client in cluster %s: %v", cfg.Region, err)
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
proxmox[idx] = pxCluster{client: client, region: cfg.Region}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &client{
|
||||||
|
config: config,
|
||||||
|
proxmox: proxmox,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) GetProxmoxCluster(region string) (*pxCluster, error) {
|
||||||
|
for _, px := range c.proxmox {
|
||||||
|
if px.region == region {
|
||||||
|
return &px, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package proxmox is main CCM defenition.
|
||||||
package proxmox
|
package proxmox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -37,7 +38,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newCloud(config *cloudConfig) (cloudprovider.Interface, error) {
|
func newCloud(config *cloudConfig) (cloudprovider.Interface, error) {
|
||||||
client, err := newClient(context.Background(), config)
|
client, err := newClient(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -62,6 +63,14 @@ func (c *cloud) Initialize(clientBuilder cloudprovider.ControllerClientBuilder,
|
|||||||
c.ctx = ctx
|
c.ctx = ctx
|
||||||
c.stop = cancel
|
c.stop = cancel
|
||||||
|
|
||||||
|
for _, px := range c.client.proxmox {
|
||||||
|
if _, err := px.client.GetVersion(); err != nil {
|
||||||
|
klog.Errorf("failed to initialized proxmox client on region %s: %v", px.region, err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Broadcast the upstream stop signal to all provider-level goroutines
|
// Broadcast the upstream stop signal to all provider-level goroutines
|
||||||
// watching the provider's context for cancellation.
|
// watching the provider's context for cancellation.
|
||||||
go func(provider *cloud) {
|
go func(provider *cloud) {
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type cloudConfig struct {
|
type cloudConfig struct {
|
||||||
Global struct {
|
Clusters []struct {
|
||||||
} `yaml:"global,omitempty"`
|
URL string `yaml:"url"`
|
||||||
|
Insecure bool `yaml:"insecure,omitempty"`
|
||||||
|
TokenID string `yaml:"token_id,omitempty"`
|
||||||
|
TokenSecret string `yaml:"token_secret,omitempty"`
|
||||||
|
Region string `yaml:"region,omitempty"`
|
||||||
|
} `yaml:"clusters,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func readCloudConfig(config io.Reader) (cloudConfig, error) {
|
func readCloudConfig(config io.Reader) (cloudConfig, error) {
|
||||||
@@ -22,7 +25,7 @@ func readCloudConfig(config io.Reader) (cloudConfig, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
klog.V(4).Infof("cloudConfig: %+v", cfg)
|
// klog.V(5).Infof("cloudConfig: %+v", cfg)
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,16 @@ package proxmox
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
pxapi "github.com/Telmate/proxmox-api-go/proxmox"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
cloudprovider "k8s.io/cloud-provider"
|
cloudprovider "k8s.io/cloud-provider"
|
||||||
|
cloudproviderapi "k8s.io/cloud-provider/api"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,6 +30,23 @@ func newInstances(client *client) *instances {
|
|||||||
func (i *instances) InstanceExists(_ context.Context, node *v1.Node) (bool, error) {
|
func (i *instances) InstanceExists(_ context.Context, node *v1.Node) (bool, error) {
|
||||||
klog.V(4).Info("instances.InstanceExists() called node: ", node.Name)
|
klog.V(4).Info("instances.InstanceExists() called node: ", node.Name)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(node.Spec.ProviderID, ProviderName) {
|
||||||
|
klog.V(4).Infof("instances.InstanceExists() node %s has foreign providerID: %s, skipped", node.Name, node.Spec.ProviderID)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err := i.getInstance(node)
|
||||||
|
if err != nil {
|
||||||
|
if err == cloudprovider.InstanceNotFound {
|
||||||
|
klog.V(4).Infof("instances.InstanceExists() instance %s not found", node.Name)
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +55,32 @@ func (i *instances) InstanceExists(_ context.Context, node *v1.Node) (bool, erro
|
|||||||
func (i *instances) InstanceShutdown(_ context.Context, node *v1.Node) (bool, error) {
|
func (i *instances) InstanceShutdown(_ context.Context, node *v1.Node) (bool, error) {
|
||||||
klog.V(4).Info("instances.InstanceShutdown() called, node: ", node.Name)
|
klog.V(4).Info("instances.InstanceShutdown() called, node: ", node.Name)
|
||||||
|
|
||||||
return true, nil
|
if !strings.HasPrefix(node.Spec.ProviderID, ProviderName) {
|
||||||
|
klog.V(4).Infof("instances.InstanceShutdown() node %s has foreign providerID: %s, skipped", node.Name, node.Spec.ProviderID)
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vmRef, region, err := i.getInstance(node)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
px, err := i.c.GetProxmoxCluster(region)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vmState, err := px.client.GetVmState(vmRef)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmState["status"].(string) == "stopped" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstanceMetadata returns the instance's metadata. The values returned in InstanceMetadata are
|
// InstanceMetadata returns the instance's metadata. The values returned in InstanceMetadata are
|
||||||
@@ -40,5 +89,125 @@ func (i *instances) InstanceShutdown(_ context.Context, node *v1.Node) (bool, er
|
|||||||
func (i *instances) InstanceMetadata(_ context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
|
func (i *instances) InstanceMetadata(_ context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
|
||||||
klog.V(4).Info("instances.InstanceMetadata() called, node: ", node.Name)
|
klog.V(4).Info("instances.InstanceMetadata() called, node: ", node.Name)
|
||||||
|
|
||||||
|
if providedIP, ok := node.ObjectMeta.Annotations[cloudproviderapi.AnnotationAlphaProvidedIPAddr]; ok {
|
||||||
|
var (
|
||||||
|
vmRef *pxapi.VmRef
|
||||||
|
region string
|
||||||
|
)
|
||||||
|
|
||||||
|
providerID := node.Spec.ProviderID
|
||||||
|
if providerID == "" {
|
||||||
|
klog.V(4).Infof("instances.InstanceMetadata() - trying to find providerID for node %s", node.Name)
|
||||||
|
|
||||||
|
for _, px := range i.c.proxmox {
|
||||||
|
vm, err := px.client.GetVmRefByName(node.Name)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
vmRef = vm
|
||||||
|
region = px.region
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if !strings.HasPrefix(node.Spec.ProviderID, ProviderName) {
|
||||||
|
klog.V(4).Infof("instances.InstanceMetadata() node %s has foreign providerID: %s, skipped", node.Name, node.Spec.ProviderID)
|
||||||
|
|
||||||
|
return &cloudprovider.InstanceMetadata{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmRef == nil {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
vmRef, region, err = i.getInstance(node)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addresses := []v1.NodeAddress{{Type: v1.NodeInternalIP, Address: providedIP}}
|
||||||
|
addresses = append(addresses, v1.NodeAddress{Type: v1.NodeHostName, Address: node.Name})
|
||||||
|
|
||||||
|
providerID = fmt.Sprintf("%s://%s/%d", ProviderName, region, vmRef.VmId())
|
||||||
|
|
||||||
|
instanceType, err := i.getInstanceType(vmRef, region)
|
||||||
|
if err != nil {
|
||||||
|
instanceType = vmRef.GetVmType()
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cloudprovider.InstanceMetadata{
|
||||||
|
ProviderID: providerID,
|
||||||
|
NodeAddresses: addresses,
|
||||||
|
InstanceType: instanceType,
|
||||||
|
Zone: vmRef.Node(),
|
||||||
|
Region: region,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return &cloudprovider.InstanceMetadata{}, nil
|
return &cloudprovider.InstanceMetadata{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *instances) getInstance(node *v1.Node) (*pxapi.VmRef, string, error) {
|
||||||
|
if !strings.HasPrefix(node.Spec.ProviderID, ProviderName) {
|
||||||
|
klog.V(4).Infof("instances.getInstance() node %s has foreign providerID: %s, skipped", node.Name, node.Spec.ProviderID)
|
||||||
|
|
||||||
|
return nil, "", fmt.Errorf("node %s has foreign providerID: %s", node.Name, node.Spec.ProviderID)
|
||||||
|
}
|
||||||
|
|
||||||
|
vmid, region, err := i.parseProviderID(node.Spec.ProviderID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
vmRef := pxapi.NewVmRef(vmid)
|
||||||
|
|
||||||
|
px, err := i.c.GetProxmoxCluster(region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
vmInfo, err := px.client.GetVmInfo(vmRef)
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "not found") {
|
||||||
|
return nil, "", cloudprovider.InstanceNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
klog.V(5).Infof("instances.getInstance() vmInfo %+v", vmInfo)
|
||||||
|
|
||||||
|
return vmRef, region, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *instances) getInstanceType(vmRef *pxapi.VmRef, region string) (string, error) {
|
||||||
|
px, err := i.c.GetProxmoxCluster(region)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
vmInfo, err := px.client.GetVmInfo(vmRef)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%.0fVCPU-%.0fGB",
|
||||||
|
vmInfo["maxcpu"].(float64),
|
||||||
|
vmInfo["maxmem"].(float64)/1024/1024/1024), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var providerIDRegexp = regexp.MustCompile(`^` + ProviderName + `://([^/]*)/([^/]+)$`)
|
||||||
|
|
||||||
|
func (i *instances) parseProviderID(providerID string) (int, string, error) {
|
||||||
|
matches := providerIDRegexp.FindStringSubmatch(providerID)
|
||||||
|
if len(matches) != 3 {
|
||||||
|
return 0, "", fmt.Errorf("ProviderID \"%s\" didn't match expected format \"%s://region/InstanceID\"", providerID, ProviderName)
|
||||||
|
}
|
||||||
|
|
||||||
|
vmID, err := strconv.Atoi(matches[2])
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return vmID, matches[1], nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user