diff --git a/cmd/main.go b/cmd/main.go index 5d030ad6..8cc6b38f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -24,6 +24,7 @@ import ( "fmt" "net/http" "os" + "strings" "github.com/go-logr/logr" "github.com/luthermonson/go-proxmox" @@ -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 proxmoxInsecure bool proxmoxRootCertFile string @@ -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" { + opts = append(opts, goproxmox.WithCalcOnlyRunning()) + } + + return goproxmox.NewAPIClient(ctx, logger, ProxmoxURL, opts...) } func initFlagsAndEnv(fs *pflag.FlagSet) { @@ -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", "") fs.BoolVar(&proxmoxInsecure, "proxmox-insecure", env.GetString("PROXMOX_INSECURE", "true") == "true", diff --git a/pkg/proxmox/goproxmox/api_client.go b/pkg/proxmox/goproxmox/api_client.go index 9139a091..8887dc7d 100644 --- a/pkg/proxmox/goproxmox/api_client.go +++ b/pkg/proxmox/goproxmox/api_client.go @@ -39,18 +39,40 @@ 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) { + 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) + } + } 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) @@ -58,10 +80,14 @@ func NewAPIClient(ctx context.Context, logger logr.Logger, baseURL string, optio 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 } // CloneVM clones a VM based on templateID and VMCloneRequest. @@ -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 { diff --git a/pkg/scope/cluster.go b/pkg/scope/cluster.go index 1fe30a99..3dea79b2 100644 --- a/pkg/scope/cluster.go +++ b/pkg/scope/cluster.go @@ -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"] @@ -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.