Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"fmt"
"net/http"
"os"
"strings"

"github.com/go-logr/logr"
"github.com/luthermonson/go-proxmox"
Expand Down Expand Up @@ -69,7 +70,8 @@ var (
// ProxmoxTokenID env variable that defines the Proxmox token id.
ProxmoxTokenID string
// ProxmoxSecret env variable that defines the Proxmox secret for the given token id.
ProxmoxSecret string
ProxmoxSecret string
ProxmoxReserveOnlyRunning string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this variable isn't particularly descriptive and it's missing a comment.
The type should be bool.


proxmoxInsecure bool
proxmoxRootCertFile string
Expand Down Expand Up @@ -208,10 +210,12 @@ func setupProxmoxClient(ctx context.Context, logger logr.Logger) (capmox.Client,
}

httpClient := &http.Client{Transport: tr}
return goproxmox.NewAPIClient(ctx, logger, ProxmoxURL,
proxmox.WithHTTPClient(httpClient),
proxmox.WithAPIToken(ProxmoxTokenID, ProxmoxSecret),
)
opts := []any{proxmox.WithHTTPClient(httpClient), proxmox.WithAPIToken(ProxmoxTokenID, ProxmoxSecret)}
if strings.ToLower(ProxmoxReserveOnlyRunning) == "true" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a bool.

opts = append(opts, goproxmox.WithCalcOnlyRunning())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be better to set it as field in the cluster/machine spec?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree.

Copy link
Author

@deepdivenow deepdivenow Mar 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be better to set it as field in the cluster/machine spec?

Maybe on Cluster scope, on mashine scope need special config structure for each physical node in physical proxmox Cluster.
proxmoxmachines.infrastructure.cluster.x-k8s.io is virtualMashine and very strange set this option here (not For Physical mashine|node)

}

return goproxmox.NewAPIClient(ctx, logger, ProxmoxURL, opts...)
}

func initFlagsAndEnv(fs *pflag.FlagSet) {
Expand All @@ -220,6 +224,7 @@ func initFlagsAndEnv(fs *pflag.FlagSet) {
ProxmoxURL = env.GetString("PROXMOX_URL", "")
ProxmoxTokenID = env.GetString("PROXMOX_TOKEN", "")
ProxmoxSecret = env.GetString("PROXMOX_SECRET", "")
ProxmoxReserveOnlyRunning = env.GetString("PROXMOX_RESERVE_ONLY_RUNNING", "")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new environment variable needs user documentation.


fs.BoolVar(&proxmoxInsecure, "proxmox-insecure",
env.GetString("PROXMOX_INSECURE", "true") == "true",
Expand Down
41 changes: 35 additions & 6 deletions pkg/proxmox/goproxmox/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,55 @@ var ErrVMIDFree = errors.New("VMID is free")
// APIClient Proxmox API client object.
type APIClient struct {
*proxmox.Client
logger logr.Logger
logger logr.Logger
reserveOnlyRunning bool
}

type Option func(*APIClient)

func WithCalcOnlyRunning() Option {
return func(c *APIClient) {
c.reserveOnlyRunning = true
}
}

// NewAPIClient initializes a Proxmox API client. If the client is misconfigured, an error is returned.
func NewAPIClient(ctx context.Context, logger logr.Logger, baseURL string, options ...proxmox.Option) (*APIClient, error) {
// options can be goproxmox.Option or proxmox.Option
func NewAPIClient(ctx context.Context, logger logr.Logger, baseURL string, options ...any) (*APIClient, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely not ...any.

var pOpts []proxmox.Option
var apiOpts []Option
for _, option := range options {
switch o := option.(type) {
case proxmox.Option:
pOpts = append(pOpts, o)
case Option:
apiOpts = append(apiOpts, o)
default:
return nil, fmt.Errorf("invalid option %T", option)
}
}
Comment on lines +57 to +68
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should've been a type.

Copy link
Author

@deepdivenow deepdivenow Mar 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you get example
How to not use "any", if we have type from upstream library "proxmox.Option", and we need local type in this library?

proxmoxAPIURL, err := url.JoinPath(baseURL, "api2", "json")
if err != nil {
return nil, fmt.Errorf("invalid proxmox base URL %q: %w", baseURL, err)
}

options = append(options, proxmox.WithLogger(capmox.Logger{}))
upstreamClient := proxmox.NewClient(proxmoxAPIURL, options...)
pOpts = append(pOpts, proxmox.WithLogger(capmox.Logger{}))
upstreamClient := proxmox.NewClient(proxmoxAPIURL, pOpts...)
version, err := upstreamClient.Version(ctx)
if err != nil {
return nil, fmt.Errorf("unable to initialize proxmox api client: %w", err)
}
logger.Info("Proxmox client initialized")
logger.Info("Proxmox server", "version", version.Release)

return &APIClient{
ac := &APIClient{
Client: upstreamClient,
logger: logger,
}, nil
}
for _, o := range apiOpts {
o(ac)
}
return ac, nil
Comment on lines -61 to +90
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

}

// CloneVM clones a VM based on templateID and VMCloneRequest.
Expand Down Expand Up @@ -275,6 +301,9 @@ func (c *APIClient) GetReservableMemoryBytes(ctx context.Context, nodeName strin
if vm.Template {
continue
}
if !vm.IsRunning() && c.reserveOnlyRunning {
continue
}
if reservableMemory < vm.MaxMem {
reservableMemory = 0
} else {
Expand Down
10 changes: 6 additions & 4 deletions pkg/scope/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ func (s *ClusterScope) setupProxmoxClient(ctx context.Context) (capmox.Client, e
token := string(secret.Data["token"])
tokenSecret := string(secret.Data["secret"])
url := string(secret.Data["url"])
calcOnlyRunning := string(secret.Data["reserveOnlyRunning"])

tlsInsecure, tlsInsecureSet := secret.Data["insecure"]
tlsRootCA := secret.Data["root_ca"]
Expand All @@ -176,10 +177,11 @@ func (s *ClusterScope) setupProxmoxClient(ctx context.Context) (capmox.Client, e
}

httpClient := &http.Client{Transport: tr}
return goproxmox.NewAPIClient(ctx, *s.Logger, url,
proxmox.WithHTTPClient(httpClient),
proxmox.WithAPIToken(token, tokenSecret),
)
opts := []any{proxmox.WithHTTPClient(httpClient), proxmox.WithAPIToken(token, tokenSecret)}
if strings.ToLower(calcOnlyRunning) == "true" {
opts = append(opts, goproxmox.WithCalcOnlyRunning())
}
return goproxmox.NewAPIClient(ctx, *s.Logger, url, opts...)
}

// Name returns the CAPI cluster name.
Expand Down
Loading