From 0cf1a4080205c5c4efa4abea9783c9ee59ffa24e Mon Sep 17 00:00:00 2001 From: Serge Logvinov Date: Mon, 8 Sep 2025 19:52:48 +0700 Subject: [PATCH] refactor: change proxmox api go module New proxmox api modules * luthermonson/go-proxmox * sergelogvinov/go-proxmox Signed-off-by: Serge Logvinov --- Dockerfile | 4 +- go.mod | 36 ++-- go.sum | 84 +++++--- pkg/provider/provider.go | 12 +- pkg/provider/provider_test.go | 3 +- pkg/proxmox/cloud.go | 29 ++- pkg/proxmox/instance_addresses.go | 32 +-- pkg/proxmox/instances.go | 51 ++--- pkg/proxmox/instances_test.go | 75 ++++--- pkg/proxmoxpool/pool.go | 327 ++++++++++++++---------------- pkg/proxmoxpool/pool_test.go | 157 +------------- 11 files changed, 352 insertions(+), 458 deletions(-) diff --git a/Dockerfile b/Dockerfile index 07b951f..000e8eb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 diff --git a/go.mod b/go.mod index b792963..9534bef 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 9ea558c..5683419 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 4635a8d..26c0ad0 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -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 } diff --git a/pkg/provider/provider_test.go b/pkg/provider/provider_test.go index 75a7eb4..58f7cc7 100644 --- a/pkg/provider/provider_test.go +++ b/pkg/provider/provider_test.go @@ -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) } }) diff --git a/pkg/proxmox/cloud.go b/pkg/proxmox/cloud.go index 493c178..5925e15 100644 --- a/pkg/proxmox/cloud.go +++ b/pkg/proxmox/cloud.go @@ -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") } diff --git a/pkg/proxmox/instance_addresses.go b/pkg/proxmox/instance_addresses.go index 4956311..d134708 100644 --- a/pkg/proxmox/instance_addresses.go +++ b/pkg/proxmox/instance_addresses.go @@ -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 } diff --git a/pkg/proxmox/instances.go b/pkg/proxmox/instances.go index e0034b1..49fb1ec 100644 --- a/pkg/proxmox/instances.go +++ b/pkg/proxmox/instances.go @@ -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 diff --git a/pkg/proxmox/instances_test.go b/pkg/proxmox/instances_test.go index bbece20..5c82e32 100644 --- a/pkg/proxmox/instances_test.go +++ b/pkg/proxmox/instances_test.go @@ -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", diff --git a/pkg/proxmoxpool/pool.go b/pkg/proxmoxpool/pool.go index 58fc810..1326c7a 100644 --- a/pkg/proxmoxpool/pool.go +++ b/pkg/proxmoxpool/pool.go @@ -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) { diff --git a/pkg/proxmoxpool/pool_test.go b/pkg/proxmoxpool/pool_test.go index 5f1c391..6754ee2 100644 --- a/pkg/proxmoxpool/pool_test.go +++ b/pkg/proxmoxpool/pool_test.go @@ -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) - } - }) - } -}