refactor: change proxmox api go module

New proxmox api modules
* luthermonson/go-proxmox
* sergelogvinov/go-proxmox

Signed-off-by: Serge Logvinov <serge.logvinov@sinextra.dev>
This commit is contained in:
Serge Logvinov
2025-09-08 19:52:48 +07:00
committed by Serge
parent 0cfad86361
commit 0cf1a40802
11 changed files with 352 additions and 458 deletions

View File

@@ -1,7 +1,7 @@
# syntax = docker/dockerfile:1.17
# syntax = docker/dockerfile:1.18
########################################
FROM --platform=${BUILDPLATFORM} golang:1.25.0-alpine AS builder
FROM --platform=${BUILDPLATFORM} golang:1.25.1-alpine AS builder
RUN apk update && apk add --no-cache make
ENV GO111MODULE=on
WORKDIR /src

36
go.mod
View File

@@ -1,11 +1,14 @@
module github.com/sergelogvinov/proxmox-cloud-controller-manager
go 1.25.0
go 1.25.1
// replace github.com/sergelogvinov/go-proxmox => ../proxmox/go-proxmox
require (
github.com/Telmate/proxmox-api-go v0.0.0-20250202141955-0f3daee49334
github.com/jarcoal/httpmock v1.4.1
github.com/luthermonson/go-proxmox v0.2.3-0.20250815182455-16138a778fb5
github.com/pkg/errors v0.9.1
github.com/sergelogvinov/go-proxmox v0.0.0-20250909122813-13b553e5a6c1
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
gopkg.in/yaml.v3 v3.0.1
@@ -24,11 +27,14 @@ require (
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/buger/goterm v1.0.4 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.6.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/diskfs/go-diskfs v1.7.0 // indirect
github.com/djherbis/times v1.6.0 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
@@ -45,21 +51,25 @@ require (
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/magefile/mage v1.15.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.23.0 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/spf13/cobra v1.10.1 // indirect
github.com/stoewer/go-strcase v1.3.1 // indirect
@@ -76,7 +86,7 @@ require (
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
go.opentelemetry.io/proto/otlp v1.8.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
@@ -84,24 +94,24 @@ require (
golang.org/x/crypto v0.41.0 // indirect
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/term v0.34.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/oauth2 v0.31.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/time v0.13.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
google.golang.org/grpc v1.75.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
k8s.io/apiserver v0.34.0 // indirect
k8s.io/component-helpers v0.34.0 // indirect
k8s.io/controller-manager v0.34.0 // indirect
k8s.io/kms v0.34.0 // indirect
k8s.io/kube-openapi v0.0.0-20250814151709-d7b6acb124c3 // indirect
k8s.io/kube-openapi v0.0.0-20250905212525-66792eed8611 // indirect
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect

84
go.sum
View File

@@ -4,14 +4,16 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/Telmate/proxmox-api-go v0.0.0-20250202141955-0f3daee49334 h1:Zp0bWj3jviVC9ppfqOwYkmMESBcIFLlzHEBK7DduBNA=
github.com/Telmate/proxmox-api-go v0.0.0-20250202141955-0f3daee49334/go.mod h1:6qNnkqdMB+22ytC/5qGAIIqtdK9egN1b/Sqs9tB/i1Y=
github.com/anchore/go-lzo v0.1.0 h1:NgAacnzqPeGH49Ky19QKLBZEuFRqtTG9cdaucc3Vncs=
github.com/anchore/go-lzo v0.1.0/go.mod h1:3kLx0bve2oN1iDwgM1U5zGku1Tfbdb0No5qp1eL1fIk=
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
@@ -27,8 +29,14 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/diskfs/go-diskfs v1.7.0 h1:vonWmt5CMowXwUc79jWyGrf2DIMeoOjkLlMnQYGVOs8=
github.com/diskfs/go-diskfs v1.7.0/go.mod h1:LhQyXqOugWFRahYUSw47NyZJPezFzB9UELwhpszLP/k=
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1UgjJdAAhj+uPL68n7XASS6bU+07ZX1WJvVS2eyoeY=
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
@@ -52,6 +60,8 @@ github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZ
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
@@ -81,10 +91,16 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jarcoal/httpmock v1.4.1 h1:0Ju+VCFuARfFlhVXFc2HxlcQkfB+Xq12/EotHko+x2A=
github.com/jarcoal/httpmock v1.4.1/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -101,6 +117,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/luthermonson/go-proxmox v0.2.3-0.20250815182455-16138a778fb5 h1:h6CrPRNBa8gcKA6s39D0ZdTnmCzxUuBOBD4kue5g8Ho=
github.com/luthermonson/go-proxmox v0.2.3-0.20250815182455-16138a778fb5/go.mod h1:oyFgg2WwTEIF0rP6ppjiixOHa5ebK1p8OaRiFhvICBQ=
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/maxatome/go-testdeep v1.14.0 h1:rRlLv1+kI8eOI3OaBXZwb3O7xY3exRzdW5QyX48g9wI=
@@ -119,24 +139,32 @@ github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sergelogvinov/go-proxmox v0.0.0-20250909122813-13b553e5a6c1 h1:awpA36jNMksizuCxPnLtdwUsSpMlFyK9z08h0JaM5ik=
github.com/sergelogvinov/go-proxmox v0.0.0-20250909122813-13b553e5a6c1/go.mod h1:vSTg/WC771SByc5087tu7uyGaXUv6fS8q3ak2X+xwqk=
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0=
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
@@ -159,6 +187,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
@@ -199,8 +229,8 @@ go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
go.opentelemetry.io/proto/otlp v1.8.0 h1:fRAZQDcAFHySxpJ1TwlA1cJ4tvcrw7nXl9xWWC8N5CE=
go.opentelemetry.io/proto/otlp v1.8.0/go.mod h1:tIeYOeNBU4cvmPqpaji1P+KbB4Oloai8wN4rWzRrFF0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -226,27 +256,29 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -270,8 +302,8 @@ google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXn
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
@@ -299,8 +331,8 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kms v0.34.0 h1:u+/rcxQ3Jr7gC9AY5nXuEnBcGEB7ZOIJ9cdLdyHyEjQ=
k8s.io/kms v0.34.0/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM=
k8s.io/kube-openapi v0.0.0-20250814151709-d7b6acb124c3 h1:liMHz39T5dJO1aOKHLvwaCjDbf07wVh6yaUlTpunnkE=
k8s.io/kube-openapi v0.0.0-20250814151709-d7b6acb124c3/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
k8s.io/kube-openapi v0.0.0-20250905212525-66792eed8611 h1:o4oKOsvSymDkZRsMAPZU7bRdwL+lPOK5VS10Dr1D6eg=
k8s.io/kube-openapi v0.0.0-20250905212525-66792eed8611/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0=
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 h1:qPrZsv1cwQiFeieFlRqT627fVZ+tyfou/+S5S0H5ua0=

View File

@@ -22,8 +22,6 @@ import (
"regexp"
"strconv"
"strings"
"github.com/Telmate/proxmox-api-go/proxmox"
)
const (
@@ -63,20 +61,20 @@ func GetVMID(providerID string) (int, error) {
}
// ParseProviderID returns the VmRef and region from the providerID.
func ParseProviderID(providerID string) (*proxmox.VmRef, string, error) {
func ParseProviderID(providerID string) (int, string, error) {
if !strings.HasPrefix(providerID, ProviderName) {
return nil, "", fmt.Errorf("foreign providerID or empty \"%s\"", providerID)
return 0, "", fmt.Errorf("foreign providerID or empty \"%s\"", providerID)
}
matches := providerIDRegexp.FindStringSubmatch(providerID)
if len(matches) != 3 {
return nil, "", fmt.Errorf("providerID \"%s\" didn't match expected format \"%s://region/InstanceID\"", providerID, ProviderName)
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 nil, "", fmt.Errorf("InstanceID have to be a number, but got \"%s\"", matches[2])
return 0, "", fmt.Errorf("InstanceID have to be a number, but got \"%s\"", matches[2])
}
return proxmox.NewVmRef(vmID), matches[1], nil
return vmID, matches[1], nil
}

View File

@@ -177,8 +177,7 @@ func TestParseProviderID(t *testing.T) {
assert.NotNil(t, err)
assert.EqualError(t, err, testCase.expectedError.Error())
} else {
assert.NotNil(t, vmr)
assert.Equal(t, testCase.expectedvmID, vmr.VmId())
assert.Equal(t, testCase.expectedvmID, vmr)
assert.Equal(t, testCase.expectedRegion, region)
}
})

View File

@@ -69,27 +69,26 @@ func init() {
}
func newCloud(config *ccmConfig.ClustersConfig) (cloudprovider.Interface, error) {
client, err := newClient(config.Clusters)
ctx, cancel := context.WithCancel(context.Background())
px, err := pxpool.NewProxmoxPool(ctx, config.Clusters)
if err != nil {
cancel()
return nil, err
}
client := &client{
pxpool: px,
}
instancesInterface := newInstances(client, config.Features)
return &cloud{
client: client,
instancesV2: instancesInterface,
}, nil
}
func newClient(clusters []*pxpool.ProxmoxCluster) (*client, error) {
px, err := pxpool.NewProxmoxPool(clusters, nil)
if err != nil {
return nil, err
}
return &client{
pxpool: px,
ctx: ctx,
stop: cancel,
}, nil
}
@@ -101,11 +100,7 @@ func (c *cloud) Initialize(clientBuilder cloudprovider.ControllerClientBuilder,
klog.InfoS("clientset initialized")
ctx, cancel := context.WithCancel(context.Background())
c.ctx = ctx
c.stop = cancel
err := c.client.pxpool.CheckClusters(ctx)
err := c.client.pxpool.CheckClusters(c.ctx)
if err != nil {
klog.ErrorS(err, "failed to check proxmox cluster")
}

View File

@@ -25,7 +25,7 @@ import (
"sort"
"strings"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/luthermonson/go-proxmox"
providerconfig "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/config"
metrics "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/metrics"
@@ -116,10 +116,7 @@ func (i *instances) addresses(ctx context.Context, node *v1.Node, info *instance
func (i *instances) retrieveQemuAddresses(ctx context.Context, info *instanceInfo) ([]v1.NodeAddress, error) {
var addresses []v1.NodeAddress
vmRef := proxmox.NewVmRef(info.ID)
vmRef.SetNode(info.Node)
nics, err := i.getInstanceNics(ctx, vmRef, info.Region)
nics, err := i.getInstanceNics(ctx, info)
if err != nil {
return nil, err
}
@@ -130,15 +127,16 @@ func (i *instances) retrieveQemuAddresses(ctx context.Context, info *instanceInf
continue
}
for _, ip := range nic.IpAddresses {
i.processIP(ctx, &addresses, ip)
for _, ip := range nic.IPAddresses {
i.processIP(ctx, &addresses, ip.IPAddress)
}
}
return addresses, nil
}
func (i *instances) processIP(_ context.Context, addresses *[]v1.NodeAddress, ip net.IP) {
func (i *instances) processIP(_ context.Context, addresses *[]v1.NodeAddress, addr string) {
ip := net.ParseIP(addr)
if ip == nil || ip.IsLoopback() {
return
}
@@ -166,17 +164,27 @@ func (i *instances) processIP(_ context.Context, addresses *[]v1.NodeAddress, ip
})
}
func (i *instances) getInstanceNics(ctx context.Context, vmRef *proxmox.VmRef, region string) ([]proxmox.AgentNetworkInterface, error) {
result := make([]proxmox.AgentNetworkInterface, 0)
func (i *instances) getInstanceNics(ctx context.Context, info *instanceInfo) ([]*proxmox.AgentNetworkIface, error) {
result := make([]*proxmox.AgentNetworkIface, 0)
px, err := i.c.pxpool.GetProxmoxCluster(region)
px, err := i.c.pxpool.GetProxmoxCluster(info.Region)
if err != nil {
return result, err
}
node, err := px.Node(ctx, info.Node)
if err != nil {
return nil, err
}
vm, err := node.VirtualMachine(ctx, info.ID)
if err != nil {
return nil, err
}
mc := metrics.NewMetricContext("getVmInfo")
nicset, err := vmRef.GetAgentInformation(ctx, px, false)
nicset, err := vm.AgentGetNetworkIFaces(ctx)
if mc.ObserveRequest(err) != nil {
return result, err
}

View File

@@ -24,8 +24,6 @@ import (
"strconv"
"strings"
"github.com/Telmate/proxmox-api-go/proxmox"
providerconfig "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/config"
metrics "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/metrics"
provider "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/provider"
@@ -142,7 +140,7 @@ func (i *instances) InstanceShutdown(ctx context.Context, node *v1.Node) (bool,
return false, nil
}
vmr, region, err := provider.ParseProviderID(node.Spec.ProviderID)
vmID, region, err := provider.ParseProviderID(node.Spec.ProviderID)
if err != nil {
klog.ErrorS(err, "instances.InstanceShutdown() failed to parse providerID", "providerID", node.Spec.ProviderID)
@@ -158,12 +156,12 @@ func (i *instances) InstanceShutdown(ctx context.Context, node *v1.Node) (bool,
mc := metrics.NewMetricContext("getVmState")
vmState, err := px.GetVmState(ctx, vmr)
vm, err := px.GetVMStatus(ctx, vmID)
if mc.ObserveRequest(err) != nil {
return false, err
}
if vmState["status"].(string) == "stopped" { //nolint:errcheck
if vm.Status == "stopped" {
return true, nil
}
@@ -258,7 +256,7 @@ func (i *instances) getInstanceInfo(ctx context.Context, node *v1.Node) (*instan
klog.V(4).InfoS("instances.getInstanceInfo() called", "node", klog.KRef("", node.Name), "provider", i.provider)
var (
vmRef *proxmox.VmRef
vmID int
region string
err error
)
@@ -270,7 +268,7 @@ func (i *instances) getInstanceInfo(ctx context.Context, node *v1.Node) (*instan
region = node.Labels[v1.LabelTopologyRegion]
}
vmID, err := strconv.Atoi(node.Annotations[AnnotationProxmoxInstanceID])
vmID, err = strconv.Atoi(node.Annotations[AnnotationProxmoxInstanceID])
if err != nil {
return nil, fmt.Errorf("instances.getInstanceInfo() parse annotation error: %v", err)
}
@@ -287,31 +285,31 @@ func (i *instances) getInstanceInfo(ctx context.Context, node *v1.Node) (*instan
mc := metrics.NewMetricContext("findVmByName")
vmRef, region, err = i.c.pxpool.FindVMByNode(ctx, node)
vmID, region, err = i.c.pxpool.FindVMByNode(ctx, node)
if mc.ObserveRequest(err) != nil {
mc := metrics.NewMetricContext("findVmByUUID")
vmRef, region, err = i.c.pxpool.FindVMByUUID(ctx, node.Status.NodeInfo.SystemUUID)
vmID, region, err = i.c.pxpool.FindVMByUUID(ctx, node.Status.NodeInfo.SystemUUID)
if mc.ObserveRequest(err) != nil {
return nil, err
}
}
if vmRef == nil {
if vmID == 0 {
return nil, cloudprovider.InstanceNotFound
}
providerID = provider.GetProviderIDFromID(region, vmRef.VmId())
providerID = provider.GetProviderIDFromID(region, vmID)
}
if vmRef == nil {
vmRef, region, err = provider.ParseProviderID(providerID)
if vmID == 0 {
vmID, region, err = provider.ParseProviderID(providerID)
if err != nil {
if i.provider == providerconfig.ProviderDefault {
return nil, fmt.Errorf("instances.getInstanceInfo() error: %v", err)
}
vmRef, region, err = i.c.pxpool.FindVMByUUID(ctx, node.Status.NodeInfo.SystemUUID)
vmID, region, err = i.c.pxpool.FindVMByUUID(ctx, node.Status.NodeInfo.SystemUUID)
if err != nil {
return nil, fmt.Errorf("instances.getInstanceInfo() error: %v", err)
}
@@ -325,7 +323,7 @@ func (i *instances) getInstanceInfo(ctx context.Context, node *v1.Node) (*instan
mc := metrics.NewMetricContext("getVmInfo")
vmConfig, err := px.GetVmConfig(ctx, vmRef)
vm, err := px.GetVMConfig(ctx, vmID)
if mc.ObserveRequest(err) != nil {
if strings.Contains(err.Error(), "not found") {
return nil, cloudprovider.InstanceNotFound
@@ -335,12 +333,12 @@ func (i *instances) getInstanceInfo(ctx context.Context, node *v1.Node) (*instan
}
info := &instanceInfo{
ID: vmRef.VmId(),
UUID: i.c.pxpool.GetVMUUID(vmConfig),
Name: i.c.pxpool.GetVMName(vmConfig),
Node: vmRef.Node().String(),
ID: vmID,
UUID: i.c.pxpool.GetVMUUID(vm),
Name: vm.Name,
Node: vm.Node,
Region: region,
Zone: vmRef.Node().String(),
Zone: vm.Node,
}
if info.UUID != node.Status.NodeInfo.SystemUUID {
@@ -355,18 +353,9 @@ func (i *instances) getInstanceInfo(ctx context.Context, node *v1.Node) (*instan
return nil, cloudprovider.InstanceNotFound
}
info.Type = i.c.pxpool.GetVMSKU(vmConfig)
info.Type = i.c.pxpool.GetVMSKU(vm)
if !instanceTypeNameRegexp.MatchString(info.Type) {
if vmConfig["cores"] != nil && vmConfig["memory"] != nil {
memory, err := strconv.Atoi(vmConfig["memory"].(string))
if err != nil {
return info, err
}
info.Type = fmt.Sprintf("%.0fVCPU-%.0fGB",
vmConfig["cores"].(float64), //nolint:errcheck
float64(memory)/1024)
}
info.Type = fmt.Sprintf("%dVCPU-%dGB", vm.CPUs, vm.MaxMem/1024/1024/1024)
}
return info, nil

View File

@@ -23,8 +23,10 @@ import (
"testing"
"github.com/jarcoal/httpmock"
proxmox "github.com/luthermonson/go-proxmox"
"github.com/stretchr/testify/suite"
goproxmox "github.com/sergelogvinov/go-proxmox"
providerconfig "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/config"
"github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/proxmoxpool"
@@ -59,6 +61,31 @@ clusters:
ts.T().Fatalf("failed to read config: %v", err)
}
httpmock.RegisterResponder(http.MethodGet, `=~/cluster/status`,
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]any{
"data": proxmox.NodeStatuses{{Name: "pve-1"}, {Name: "pve-2"}, {Name: "pve-3"}},
})
})
httpmock.RegisterResponder(http.MethodGet, `=~/nodes/pve-1/status`,
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]any{
"data": proxmox.Node{},
})
})
httpmock.RegisterResponder(http.MethodGet, `=~/nodes/pve-2/status`,
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]any{
"data": proxmox.Node{},
})
})
httpmock.RegisterResponder(http.MethodGet, `=~/nodes/pve-3/status`,
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]any{
"data": proxmox.Node{},
})
})
httpmock.RegisterResponderWithQuery("GET", "https://127.0.0.1:8006/api2/json/cluster/resources", "type=vm",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
@@ -95,12 +122,32 @@ clusters:
"name": "cluster-2-node-1",
"maxcpu": 1,
"maxmem": 2 * 1024 * 1024 * 1024,
"status": "stopped",
},
},
})
},
)
httpmock.RegisterResponder(http.MethodGet, `=~/nodes/pve-1/qemu/100/status/current`,
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]any{
"data": proxmox.VirtualMachine{Node: "pve-1", Name: "cluster-1-node-1", VMID: 100, CPUs: 4, MaxMem: 10 * 1024 * 1024 * 1024, Status: "running"},
})
})
httpmock.RegisterResponder(http.MethodGet, `=~/nodes/pve-2/qemu/101/status/current`,
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]any{
"data": proxmox.VirtualMachine{Node: "pve-2", Name: "cluster-1-node-2", VMID: 101, CPUs: 2, MaxMem: 5 * 1024 * 1024 * 1024, Status: "running"},
})
})
httpmock.RegisterResponder(http.MethodGet, `=~/nodes/pve-3/qemu/100/status/current`,
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]any{
"data": proxmox.VirtualMachine{Node: "pve-3", Name: "cluster-2-node-1", VMID: 100, CPUs: 1, MaxMem: 2 * 1024 * 1024 * 1024, Status: "stopped"},
})
})
httpmock.RegisterResponder("GET", "https://127.0.0.1:8006/api2/json/nodes/pve-1/qemu/100/config",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
@@ -149,27 +196,7 @@ clusters:
},
)
httpmock.RegisterResponder("GET", "https://127.0.0.1:8006/api2/json/nodes/pve-1/qemu/100/status/current",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": map[string]interface{}{
"status": "running",
},
})
},
)
httpmock.RegisterResponder("GET", "https://127.0.0.2:8006/api2/json/nodes/pve-3/qemu/100/status/current",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": map[string]interface{}{
"status": "stopped",
},
})
},
)
px, err := proxmoxpool.NewProxmoxPool(cfg.Clusters, &http.Client{})
px, err := proxmoxpool.NewProxmoxPool(ts.T().Context(), cfg.Clusters, proxmox.WithHTTPClient(&http.Client{}))
if err != nil {
ts.T().Fatalf("failed to create cluster client: %v", err)
}
@@ -374,7 +401,7 @@ func (ts *ccmTestSuite) TestInstanceShutdown() {
},
},
expected: false,
expectedError: "vm '500' not found",
expectedError: goproxmox.ErrVirtualMachineNotFound.Error(),
},
{
msg: "NodeExists",
@@ -397,7 +424,7 @@ func (ts *ccmTestSuite) TestInstanceShutdown() {
msg: "NodeExistsStopped",
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster-1-node-3",
Name: "cluster-2-node-1",
},
Spec: v1.NodeSpec{
ProviderID: "proxmox://cluster-2/100",
@@ -485,7 +512,7 @@ func (ts *ccmTestSuite) TestInstanceMetadata() {
expected *cloudprovider.InstanceMetadata
}{
{
msg: "NodeAnnotations",
msg: "NodeUndefined",
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "test-node-1",

View File

@@ -23,11 +23,12 @@ import (
"encoding/base64"
"fmt"
"net/http"
"net/url"
"os"
"strings"
"github.com/Telmate/proxmox-api-go/proxmox"
proxmox "github.com/luthermonson/go-proxmox"
goproxmox "github.com/sergelogvinov/go-proxmox"
v1 "k8s.io/api/core/v1"
"k8s.io/klog/v2"
@@ -37,28 +38,38 @@ import (
type ProxmoxCluster struct {
URL string `yaml:"url"`
Insecure bool `yaml:"insecure,omitempty"`
TokenIDFile string `yaml:"token_id_file,omitempty"`
TokenSecretFile string `yaml:"token_secret_file,omitempty"`
TokenID string `yaml:"token_id,omitempty"`
TokenIDFile string `yaml:"token_id_file,omitempty"`
TokenSecret string `yaml:"token_secret,omitempty"`
TokenSecretFile string `yaml:"token_secret_file,omitempty"`
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
Region string `yaml:"region,omitempty"`
}
// ProxmoxPool is a Proxmox client.
// ProxmoxPool is a Proxmox client pool of proxmox clusters.
type ProxmoxPool struct {
clients map[string]*proxmox.Client
clients map[string]*goproxmox.APIClient
}
// NewProxmoxPool creates a new Proxmox cluster client.
func NewProxmoxPool(config []*ProxmoxCluster, hClient *http.Client) (*ProxmoxPool, error) {
func NewProxmoxPool(ctx context.Context, config []*ProxmoxCluster, options ...proxmox.Option) (*ProxmoxPool, error) {
clusters := len(config)
if clusters > 0 {
clients := make(map[string]*proxmox.Client, clusters)
clients := make(map[string]*goproxmox.APIClient, clusters)
for _, cfg := range config {
if cfg.TokenID == "" {
options = append(options, proxmox.WithUserAgent("ProxmoxCCM v1.0"))
if cfg.Insecure {
httpTr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
options = append(options, proxmox.WithHTTPClient(&http.Client{Transport: httpTr}))
}
if cfg.TokenID == "" && cfg.TokenIDFile != "" {
var err error
cfg.TokenID, err = readValueFromFile(cfg.TokenIDFile)
@@ -67,7 +78,7 @@ func NewProxmoxPool(config []*ProxmoxCluster, hClient *http.Client) (*ProxmoxPoo
}
}
if cfg.TokenSecret == "" {
if cfg.TokenSecret == "" && cfg.TokenSecretFile != "" {
var err error
cfg.TokenSecret, err = readValueFromFile(cfg.TokenSecretFile)
@@ -76,25 +87,21 @@ func NewProxmoxPool(config []*ProxmoxCluster, hClient *http.Client) (*ProxmoxPoo
}
}
tlsconf := &tls.Config{InsecureSkipVerify: true}
if !cfg.Insecure {
tlsconf = nil
if cfg.Username != "" && cfg.Password != "" {
options = append(options, proxmox.WithCredentials(&proxmox.Credentials{
Username: cfg.Username,
Password: cfg.Password,
}))
} else if cfg.TokenID != "" && cfg.TokenSecret != "" {
options = append(options, proxmox.WithAPIToken(cfg.TokenID, cfg.TokenSecret))
}
pClient, err := proxmox.NewClient(cfg.URL, hClient, os.Getenv("PM_HTTP_HEADERS"), tlsconf, "", 600)
pxClient, err := goproxmox.NewAPIClient(ctx, cfg.URL, options...)
if err != nil {
return nil, err
}
if cfg.Username != "" && cfg.Password != "" {
if err := pClient.Login(context.Background(), cfg.Username, cfg.Password, ""); err != nil {
return nil, err
}
} else {
pClient.SetAPIToken(cfg.TokenID, cfg.TokenSecret)
}
clients[cfg.Region] = pClient
clients[cfg.Region] = pxClient
}
return &ProxmoxPool{
@@ -105,21 +112,33 @@ func NewProxmoxPool(config []*ProxmoxCluster, hClient *http.Client) (*ProxmoxPoo
return nil, ErrClustersNotFound
}
// GetRegions returns supported regions.
func (c *ProxmoxPool) GetRegions() []string {
regions := make([]string, 0, len(c.clients))
for region := range c.clients {
regions = append(regions, region)
}
return regions
}
// CheckClusters checks if the Proxmox connection is working.
func (c *ProxmoxPool) CheckClusters(ctx context.Context) error {
for region, pClient := range c.clients {
if _, err := pClient.GetVersion(ctx); err != nil {
for region, pxClient := range c.clients {
if _, err := pxClient.Version(ctx); err != nil {
return fmt.Errorf("failed to initialized proxmox client in region %s, error: %v", region, err)
}
vmlist, err := pClient.GetVmList(ctx)
pxCluster, err := pxClient.Cluster(ctx)
if err != nil {
return fmt.Errorf("failed to get list of VMs in region %s, error: %v", region, err)
return fmt.Errorf("failed to get cluster info in region %s, error: %v", region, err)
}
vms, ok := vmlist["data"].([]interface{})
if !ok {
return fmt.Errorf("failed to cast response to list of VMs in region %s, error: %v", region, err)
// Check if we can have permission to list VMs
vms, err := pxCluster.Resources(ctx, "vm")
if err != nil {
return fmt.Errorf("failed to get list of VMs in region %s, error: %v", region, err)
}
if len(vms) > 0 {
@@ -133,7 +152,7 @@ func (c *ProxmoxPool) CheckClusters(ctx context.Context) error {
}
// GetProxmoxCluster returns a Proxmox cluster client in a given region.
func (c *ProxmoxPool) GetProxmoxCluster(region string) (*proxmox.Client, error) {
func (c *ProxmoxPool) GetProxmoxCluster(region string) (*goproxmox.APIClient, error) {
if c.clients[region] != nil {
return c.clients[region], nil
}
@@ -141,9 +160,39 @@ func (c *ProxmoxPool) GetProxmoxCluster(region string) (*proxmox.Client, error)
return nil, ErrRegionNotFound
}
// GetVMByIDInRegion returns a Proxmox VM by its ID in a given region.
func (c *ProxmoxPool) GetVMByIDInRegion(ctx context.Context, region string, vmid uint64) (*proxmox.ClusterResource, error) {
px, err := c.GetProxmoxCluster(region)
if err != nil {
return nil, err
}
vm, err := px.FindVMByID(ctx, uint64(vmid)) //nolint: unconvert
if err != nil {
return nil, err
}
return vm, nil
}
// DeleteVMByIDInRegion deletes a Proxmox VM by its ID in a given region.
func (c *ProxmoxPool) DeleteVMByIDInRegion(ctx context.Context, region string, vm *proxmox.ClusterResource) error {
px, err := c.GetProxmoxCluster(region)
if err != nil {
return err
}
return px.DeleteVMByID(ctx, vm.Node, int(vm.VMID))
}
// GetNodeGroup returns a Proxmox node ha-group in a given region.
func (c *ProxmoxPool) GetNodeGroup(ctx context.Context, region string, node string) (string, error) {
haGroups, err := c.GetHAGroupList(ctx, region)
px, err := c.GetProxmoxCluster(region)
if err != nil {
return "", err
}
haGroups, err := px.GetHAGroupList(ctx)
if err != nil {
return "", fmt.Errorf("error get ha-groups %v", err)
}
@@ -153,7 +202,7 @@ func (c *ProxmoxPool) GetNodeGroup(ctx context.Context, region string, node stri
continue
}
for _, n := range g.Nodes {
for _, n := range strings.Split(g.Nodes, ",") {
if node == strings.Split(n, ":")[0] {
return g.Group, nil
}
@@ -163,183 +212,105 @@ func (c *ProxmoxPool) GetNodeGroup(ctx context.Context, region string, node stri
return "", ErrHAGroupNotFound
}
// GetHAGroupList returns a list of Proxmox ha-groups in a given region.
func (c *ProxmoxPool) GetHAGroupList(ctx context.Context, region string) (haGroups []proxmox.HAGroup, err error) {
px, err := c.GetProxmoxCluster(region)
if err != nil {
return nil, err
}
// FindVMByNode find a VM by kubernetes node resource in all Proxmox clusters.
func (c *ProxmoxPool) FindVMByNode(ctx context.Context, node *v1.Node) (vmID int, region string, err error) {
for region, px := range c.clients {
vmid, err := px.FindVMByFilter(ctx, func(rs *proxmox.ClusterResource) (bool, error) {
if rs.Type != "qemu" {
return false, nil
}
list, err := px.GetItemList(ctx, "/cluster/ha/groups")
if err != nil {
return nil, err
}
if !strings.HasPrefix(rs.Name, node.Name) {
return false, nil
}
haGroups = []proxmox.HAGroup{}
pxnode, err := px.Client.Node(ctx, rs.Node)
if err != nil {
return false, err
}
items, ok := list["data"].([]interface{})
if !ok {
return nil, fmt.Errorf("failed to cast response to list of HA groups in region %s, error: %v", region, err)
}
vm, err := pxnode.VirtualMachine(ctx, int(rs.VMID))
if err != nil {
return false, err
}
for _, item := range items {
itemMap := item.(map[string]interface{})
smbios1 := goproxmox.VMSMBIOS{}
smbios1.UnmarshalString(vm.VirtualMachineConfig.SMBios1) //nolint:errcheck
if itemMap["type"].(string) != "group" {
if smbios1.UUID == node.Status.NodeInfo.SystemUUID {
return true, nil
}
return false, nil
})
if err != nil {
if err == goproxmox.ErrVirtualMachineNotFound {
continue
}
return 0, "", err
}
if vmid == 0 {
continue
}
haGroups = append(haGroups, proxmox.HAGroup{
Group: itemMap["group"].(string),
Nodes: strings.Split(itemMap["nodes"].(string), ","),
NoFailback: itemMap["nofailback"].(float64) == 1,
Restricted: itemMap["restricted"].(float64) == 1,
Type: itemMap["type"].(string),
})
return vmid, region, nil
}
return haGroups, nil
}
// FindVMByNode find a VM by kubernetes node resource in all Proxmox clusters.
func (c *ProxmoxPool) FindVMByNode(ctx context.Context, node *v1.Node) (*proxmox.VmRef, string, error) {
for region, px := range c.clients {
vmrs, err := px.GetVmRefsByName(ctx, node.Name)
if err != nil {
if strings.Contains(err.Error(), "not found") {
continue
}
return nil, "", err
}
for _, vmr := range vmrs {
config, err := px.GetVmConfig(ctx, vmr)
if err != nil {
return nil, "", err
}
if c.GetVMUUID(config) == node.Status.NodeInfo.SystemUUID {
return vmr, region, nil
}
}
}
return nil, "", ErrInstanceNotFound
}
// FindVMByName find a VM by name in all Proxmox clusters.
func (c *ProxmoxPool) FindVMByName(ctx context.Context, name string) (*proxmox.VmRef, string, error) {
for region, px := range c.clients {
vmr, err := px.GetVmRefByName(ctx, name)
if err != nil {
if strings.Contains(err.Error(), "not found") {
continue
}
return nil, "", err
}
return vmr, region, nil
}
return nil, "", ErrInstanceNotFound
return 0, "", ErrInstanceNotFound
}
// FindVMByUUID find a VM by uuid in all Proxmox clusters.
func (c *ProxmoxPool) FindVMByUUID(ctx context.Context, uuid string) (*proxmox.VmRef, string, error) {
func (c *ProxmoxPool) FindVMByUUID(ctx context.Context, uuid string) (vmID int, region string, err error) {
for region, px := range c.clients {
vms, err := px.GetResourceList(ctx, "vm")
if err != nil {
return nil, "", fmt.Errorf("error get resources %v", err)
}
for vmii := range vms {
vm, ok := vms[vmii].(map[string]interface{})
if !ok {
return nil, "", fmt.Errorf("failed to cast response to map, vm: %v", vm)
vmid, err := px.FindVMByFilter(ctx, func(rs *proxmox.ClusterResource) (bool, error) {
if rs.Type != "qemu" {
return false, nil
}
if vm["type"].(string) != "qemu" { //nolint:errcheck
continue
}
vmr := proxmox.NewVmRef(int(vm["vmid"].(float64))) //nolint:errcheck
vmr.SetNode(vm["node"].(string)) //nolint:errcheck
vmr.SetVmType("qemu")
config, err := px.GetVmConfig(ctx, vmr)
pxnode, err := px.Client.Node(ctx, rs.Node)
if err != nil {
return nil, "", err
return false, err
}
if config["smbios1"] != nil {
if c.getSMBSetting(config, "uuid") == uuid {
return vmr, region, nil
}
vm, err := pxnode.VirtualMachine(ctx, int(rs.VMID))
if err != nil {
return false, err
}
if c.GetVMUUID(vm) == uuid {
return true, nil
}
return false, nil
})
if err != nil {
return 0, "", ErrInstanceNotFound
}
return vmid, region, nil
}
return nil, "", ErrInstanceNotFound
}
// GetVMName returns the VM name.
func (c *ProxmoxPool) GetVMName(vmInfo map[string]interface{}) string {
if vmInfo["name"] != nil {
return vmInfo["name"].(string) //nolint:errcheck
}
return ""
return 0, "", ErrInstanceNotFound
}
// GetVMUUID returns the VM UUID.
func (c *ProxmoxPool) GetVMUUID(vmInfo map[string]interface{}) string {
if vmInfo["smbios1"] != nil {
return c.getSMBSetting(vmInfo, "uuid")
}
func (c *ProxmoxPool) GetVMUUID(vm *proxmox.VirtualMachine) string {
smbios1 := goproxmox.VMSMBIOS{}
smbios1.UnmarshalString(vm.VirtualMachineConfig.SMBios1) //nolint:errcheck
return ""
return smbios1.UUID
}
// GetVMSKU returns the VM instance type name.
func (c *ProxmoxPool) GetVMSKU(vmInfo map[string]interface{}) string {
if vmInfo["smbios1"] != nil {
return c.getSMBSetting(vmInfo, "sku")
}
func (c *ProxmoxPool) GetVMSKU(vm *proxmox.VirtualMachine) string {
smbios1 := goproxmox.VMSMBIOS{}
smbios1.UnmarshalString(vm.VirtualMachineConfig.SMBios1) //nolint:errcheck
return ""
}
sku, _ := base64.StdEncoding.DecodeString(smbios1.SKU) //nolint:errcheck
func (c *ProxmoxPool) getSMBSetting(vmInfo map[string]interface{}, name string) string {
smbios, ok := vmInfo["smbios1"].(string)
if !ok {
return ""
}
for _, l := range strings.Split(smbios, ",") {
if l == "" || l == "base64=1" {
continue
}
parsedParameter, err := url.ParseQuery(l)
if err != nil {
return ""
}
for k, v := range parsedParameter {
if k == name {
decodedString, err := base64.StdEncoding.DecodeString(v[0])
if err != nil {
decodedString = []byte(v[0])
}
return string(decodedString)
}
}
}
return ""
return string(sku)
}
func readValueFromFile(path string) (string, error) {

View File

@@ -17,12 +17,9 @@ limitations under the License.
package proxmoxpool_test
import (
"fmt"
"net/http"
"os"
"testing"
"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/assert"
pxpool "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/proxmoxpool"
@@ -67,13 +64,13 @@ func TestNewClient(t *testing.T) {
cfg := newClusterEnv()
assert.NotNil(t, cfg)
pClient, err := pxpool.NewProxmoxPool([]*pxpool.ProxmoxCluster{}, nil)
pxClient, err := pxpool.NewProxmoxPool(t.Context(), []*pxpool.ProxmoxCluster{})
assert.NotNil(t, err)
assert.Nil(t, pClient)
assert.Nil(t, pxClient)
pClient, err = pxpool.NewProxmoxPool(cfg, nil)
pxClient, err = pxpool.NewProxmoxPool(t.Context(), cfg)
assert.Nil(t, err)
assert.NotNil(t, pClient)
assert.NotNil(t, pxClient)
}
func TestNewClientWithCredentialsFromFile(t *testing.T) {
@@ -92,9 +89,9 @@ func TestNewClientWithCredentialsFromFile(t *testing.T) {
cfg := newClusterEnvWithFiles(tokenIDFile.Name(), tokenSecretFile.Name())
pClient, err := pxpool.NewProxmoxPool(cfg, nil)
pxClient, err := pxpool.NewProxmoxPool(t.Context(), cfg)
assert.Nil(t, err)
assert.NotNil(t, pClient)
assert.NotNil(t, pxClient)
assert.Equal(t, "user!token-id", cfg[0].TokenID)
assert.Equal(t, "secret", cfg[0].TokenSecret)
}
@@ -103,152 +100,20 @@ func TestCheckClusters(t *testing.T) {
cfg := newClusterEnv()
assert.NotNil(t, cfg)
pClient, err := pxpool.NewProxmoxPool(cfg, nil)
pxClient, err := pxpool.NewProxmoxPool(t.Context(), cfg)
assert.Nil(t, err)
assert.NotNil(t, pClient)
assert.NotNil(t, pxClient)
pxapi, err := pClient.GetProxmoxCluster("test")
pxapi, err := pxClient.GetProxmoxCluster("test")
assert.NotNil(t, err)
assert.Nil(t, pxapi)
assert.Equal(t, pxpool.ErrRegionNotFound, err)
pxapi, err = pClient.GetProxmoxCluster("cluster-1")
pxapi, err = pxClient.GetProxmoxCluster("cluster-1")
assert.Nil(t, err)
assert.NotNil(t, pxapi)
err = pClient.CheckClusters(t.Context())
err = pxClient.CheckClusters(t.Context())
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "failed to initialized proxmox client in region")
}
func TestFindVMByNameNonExist(t *testing.T) {
cfg := newClusterEnv()
assert.NotNil(t, cfg)
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", "https://127.0.0.1:8006/api2/json/cluster/resources",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": []interface{}{
map[string]interface{}{
"node": "node-1",
"type": "qemu",
"vmid": 100,
"name": "test1-vm",
},
},
})
},
)
httpmock.RegisterResponder("GET", "https://127.0.0.2:8006/api2/json/cluster/resources",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": []interface{}{
map[string]interface{}{
"node": "node-2",
"type": "qemu",
"vmid": 100,
"name": "test2-vm",
},
},
})
},
)
pClient, err := pxpool.NewProxmoxPool(cfg, &http.Client{})
assert.Nil(t, err)
assert.NotNil(t, pClient)
vmr, cluster, err := pClient.FindVMByName(t.Context(), "non-existing-vm")
assert.NotNil(t, err)
assert.Equal(t, "", cluster)
assert.Nil(t, vmr)
assert.Equal(t, pxpool.ErrInstanceNotFound, err)
}
func TestFindVMByNameExist(t *testing.T) {
cfg := newClusterEnv()
assert.NotNil(t, cfg)
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", "https://127.0.0.1:8006/api2/json/cluster/resources",
httpmock.NewJsonResponderOrPanic(200, map[string]interface{}{
"data": []interface{}{
map[string]interface{}{
"node": "node-1",
"type": "qemu",
"vmid": 100,
"name": "test1-vm",
},
},
}),
)
httpmock.RegisterResponder("GET", "https://127.0.0.2:8006/api2/json/cluster/resources",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": []interface{}{
map[string]interface{}{
"node": "node-2",
"type": "qemu",
"vmid": 100,
"name": "test2-vm",
},
},
})
},
)
pClient, err := pxpool.NewProxmoxPool(cfg, &http.Client{})
assert.Nil(t, err)
assert.NotNil(t, pClient)
tests := []struct {
msg string
vmName string
expectedError error
expectedVMID int
expectedCluster string
}{
{
msg: "vm not found",
vmName: "non-existing-vm",
expectedError: fmt.Errorf("vm 'non-existing-vm' not found"),
},
{
msg: "Test1-VM",
vmName: "test1-vm",
expectedVMID: 100,
expectedCluster: "cluster-1",
},
{
msg: "Test2-VM",
vmName: "test2-vm",
expectedVMID: 100,
expectedCluster: "cluster-2",
},
}
for _, testCase := range tests {
t.Run(fmt.Sprint(testCase.msg), func(t *testing.T) {
vmr, cluster, err := pClient.FindVMByName(t.Context(), testCase.vmName)
if testCase.expectedError == nil {
assert.Nil(t, err)
assert.NotNil(t, vmr)
assert.Equal(t, testCase.expectedVMID, vmr.VmId())
assert.Equal(t, testCase.expectedCluster, cluster)
} else {
assert.NotNil(t, err)
assert.Equal(t, "", cluster)
assert.Nil(t, vmr)
assert.Equal(t, pxpool.ErrInstanceNotFound, err)
}
})
}
}