Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List ha resources #176

Open
wants to merge 49 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
a53a116
vzdump api call
Pivnoy Mar 13, 2024
51986f5
Merge pull request #1 from Pivnoy/vzdump
Pivnoy Mar 13, 2024
9ec5fe0
struct tag fix
Pivnoy Mar 13, 2024
1c60063
Merge pull request #2 from Pivnoy/vzdump
Pivnoy Mar 13, 2024
50b62d3
replace vzdump method based on proxmox ve api
Pivnoy Mar 15, 2024
c63ed1a
Merge pull request #3 from Pivnoy/vzdump
Pivnoy Mar 15, 2024
ff0cfce
review comment fixes
Pivnoy Mar 15, 2024
a904ff2
Merge pull request #4 from Pivnoy/vzdump
Pivnoy Mar 15, 2024
11c9af7
Merge branch 'luthermonson:main' into main
Pivnoy Mar 17, 2024
4a746d8
Merge branch 'luthermonson:main' into main
Pivnoy Mar 30, 2024
375c1b5
cluster tasks api call
Pivnoy Mar 30, 2024
c0aa37c
Merge pull request #5 from Pivnoy/cluster-tasks
Pivnoy Mar 30, 2024
6e5c7e3
add client instance to cluster task
Pivnoy Mar 30, 2024
ca9c0bb
Merge pull request #6 from Pivnoy/cluster-tasks
Pivnoy Mar 30, 2024
b620ff0
Merge branch 'luthermonson:main' into main
Pivnoy Apr 1, 2024
69ab3df
Merge branch 'luthermonson:main' into main
Pivnoy May 3, 2024
0187fca
update firewall options
Pivnoy May 3, 2024
551e941
update field types
Pivnoy May 3, 2024
4875d86
update field types
Pivnoy May 3, 2024
202a4a6
change firewall get option func
Pivnoy May 4, 2024
21bfc4a
change for common types
Pivnoy May 4, 2024
ca5f673
create ha group
Pivnoy May 13, 2024
5df326d
update path
Pivnoy May 13, 2024
037f9da
small schema changes
Pivnoy May 13, 2024
b925fac
small changes
Pivnoy May 13, 2024
bf9f1e8
drop unused field
Pivnoy May 13, 2024
ebaa0e8
get ha groups
Pivnoy May 13, 2024
ca43383
ha group delete
Pivnoy May 13, 2024
d522b89
change types
Pivnoy May 13, 2024
0c1b737
change task saved type
Pivnoy May 14, 2024
f64854b
Merge pull request #7 from Pivnoy/set-firewall-improve
Pivnoy May 29, 2024
1a1ffda
Merge pull request #8 from Pivnoy/ha-group-configuration
Pivnoy May 29, 2024
a28632e
Merge pull request #9 from Pivnoy/task-types
Pivnoy May 29, 2024
46586b7
cluster ha resources
Pivnoy May 31, 2024
55ea2ab
omitempty instruction
Pivnoy Jun 4, 2024
dfe5e57
json tag name fix
Pivnoy Jun 4, 2024
581006a
cluster ha resource delete
Pivnoy Jun 4, 2024
aee325d
Merge pull request #10 from Pivnoy/cluster_ha_resources
Pivnoy Jun 4, 2024
f26840f
Merge branch 'luthermonson:main' into main
Pivnoy Jun 17, 2024
6246749
move opt
Pivnoy Jun 17, 2024
c663bdc
Merge pull request #11 from Pivnoy/firewall-rules-move-opt
Pivnoy Jun 17, 2024
e37fc12
feat: generalize http client
Spirans Jul 4, 2024
20266e5
Merge pull request #12 from Pivnoy/http_client
Pivnoy Jul 4, 2024
c174489
feat: change type of http client for option
Spirans Jul 4, 2024
9fc28dd
Merge pull request #13 from Pivnoy/http_client
Pivnoy Jul 4, 2024
0d48950
ha resource get & list
Pivnoy Oct 25, 2024
5bea9b4
ha resource get & list
Pivnoy Oct 25, 2024
eea9958
change files
Pivnoy Oct 25, 2024
9a7a104
fix
Pivnoy Oct 25, 2024
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
121 changes: 121 additions & 0 deletions cluster_ha.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package proxmox

import (
"context"
"fmt"
"strconv"
"strings"
)

const (
PrioritySeparator = ":"
NodeSeparator = ","
)

type haGroupConfiguration struct {
Nodes string `json:"nodes"`
Group string `json:"group"`
Comment *string `json:"comment,omitempty"`
NoFailback *IntOrBool `json:"nofailback,omitempty"`
Restricted *IntOrBool `json:"restricted,omitempty"`
Type HAType `json:"type,omitempty"`
}

func (cl *Cluster) HAGroupCreate(ctx context.Context, groupConfiguration *HAGroupConfiguration) error {
if groupConfiguration == nil {
return fmt.Errorf("empty ha group configuration")
}

haGroupCfg := haGroupConfiguration{
Group: groupConfiguration.Group,
Comment: groupConfiguration.Comment,
NoFailback: groupConfiguration.NoFailback,
Restricted: groupConfiguration.Restricted,
Type: HATypeGroup,
}

var nodes []string
for _, haNode := range groupConfiguration.HaNodes {
if haNode.Priority != nil {
nodes = append(nodes,
fmt.Sprintf("%s%s%d", haNode.Node, PrioritySeparator, *haNode.Priority))
} else {
nodes = append(nodes,
haNode.Node)
}
}

haGroupCfg.Nodes = strings.Join(nodes, NodeSeparator)

if err := cl.client.Post(ctx, "/cluster/ha/groups", &haGroupCfg, nil); err != nil {
return err
}

return nil
}

func (cl *Cluster) HAGroupDelete(ctx context.Context, groupName string) error {
return cl.client.Delete(ctx, fmt.Sprintf("/cluster/ha/groups/%s", groupName), nil)
}

func (cl *Cluster) HAGroups(ctx context.Context) ([]HAGroupConfiguration, error) {
var haConfigurations []haGroupConfiguration
if err := cl.client.Get(ctx, "/cluster/ha/groups", &haConfigurations); err != nil {
return nil, err
}

haGroupConfigurations := make([]HAGroupConfiguration, 0, len(haConfigurations))

for _, groupCfg := range haConfigurations {
haNodes, err := prepareHANodeList(groupCfg.Nodes)
if err != nil {
return nil, fmt.Errorf("prepare ha node list : %w", err)
}

haGroupConfigurations = append(haGroupConfigurations, HAGroupConfiguration{
Group: groupCfg.Group,
HaNodes: haNodes,
Comment: groupCfg.Comment,
NoFailback: groupCfg.NoFailback,
Restricted: groupCfg.Restricted,
})
}

return haGroupConfigurations, nil
}

func prepareHANodeList(haNodeStr string) ([]HANodes, error) {
nodeStrs := strings.Split(haNodeStr, NodeSeparator)

haNodes := make([]HANodes, 0, len(nodeStrs))

for _, nodeStr := range nodeStrs {
haNode, err := splitToHANode(nodeStr)
if err != nil {
return nil, fmt.Errorf("split node string : %w", err)
}

haNodes = append(haNodes, haNode)
}

return haNodes, nil
}

func splitToHANode(haNodeStr string) (HANodes, error) {
haNodeParts := strings.Split(haNodeStr, PrioritySeparator)

haNode := HANodes{
Node: haNodeParts[0],
}

if len(haNodeParts) > 1 {
priority, err := strconv.ParseUint(haNodeParts[1], 10, 32)
if err != nil {
return HANodes{}, fmt.Errorf("cannot parse priority : %w", err)
}

haNode.Priority = AsPtr[uint](uint(priority))
}

return haNode, nil
}
81 changes: 81 additions & 0 deletions cluster_ha_resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package proxmox

import (
"context"
"errors"
"fmt"
"strconv"
"strings"
)

func (cl *Cluster) CreateHAResource(ctx context.Context, haResource HAResource) error {
if err := cl.client.Post(ctx, "/cluster/ha/resources", &haResource, nil); err != nil {
return err
}

return nil
}

func (cl *Cluster) DeleteHAResource(ctx context.Context, sid SID) error {
if err := cl.client.Delete(ctx, fmt.Sprintf("/cluster/ha/resources/%s:%d", sid.Type, sid.ID), nil); err != nil {
return err
}

return nil
}

func (cl *Cluster) GetHAResource(ctx context.Context, sid SID) (HAResource, error) {
var haResource HAResource
if err := cl.client.Get(ctx, fmt.Sprintf("/cluster/ha/resources/%s:%d", sid.Type, sid.ID), &haResource); err != nil {
return haResource, err
}

return haResource, nil
}

func (cl *Cluster) ListHAResources(ctx context.Context, resourceType HAResourceType) ([]HAResource, error) {
var haResources []haResource
if err := cl.client.Get(ctx, fmt.Sprintf("/cluster/ha/resources?type=%s", resourceType), &haResources); err != nil {
return nil, err
}

return fillHAResources(haResources)
}

func fillHAResources(resources []haResource) ([]HAResource, error) {
haResources := make([]HAResource, 0, len(resources))
for _, resource := range resources {
sid, err := parseSid(resource.Sid)
if err != nil {
return nil, fmt.Errorf("parse sid: %w", err)
}

haResources = append(haResources, HAResource{
ID: sid.ID,
Group: AsPtr(resource.Group),
Comment: AsPtr(resource.Comment),
MaxRelocate: AsPtr(resource.MaxRelocate),
MaxRestart: AsPtr(resource.MaxRestart),
State: AsPtr(resource.State),
})
}

return haResources, nil
}

func parseSid(sid string) (SID, error) {
sidParts := strings.Split(sid, ":")
if len(sidParts) != 2 {
return SID{}, errors.New("invalid sid parts count")
}

vmid, err := strconv.Atoi(sidParts[1])
if err != nil {
return SID{}, fmt.Errorf("parse sid vmid: %w", err)
}

return SID{
Type: HAResourceType(sidParts[0]),
ID: vmid,
}, nil
}
9 changes: 8 additions & 1 deletion options.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package proxmox

import (
"crypto/tls"
"fmt"
"net/http"
)
Expand All @@ -12,7 +13,7 @@ func WithClient(client *http.Client) Option {
return WithHTTPClient(client)
}

func WithHTTPClient(client *http.Client) Option {
func WithHTTPClient(client doer) Option {
return func(c *Client) {
c.httpClient = client
}
Expand Down Expand Up @@ -59,3 +60,9 @@ func WithLogger(logger LeveledLoggerInterface) Option {
c.log = logger
}
}

func WithTLSConfig(config *tls.Config) Option {
return func(c *Client) {
c.tlsConfig = config
}
}
14 changes: 7 additions & 7 deletions proxmox.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,13 @@
return fmt.Sprintf(TagFormat, v)
}

type doer interface {
Do(req *http.Request) (*http.Response, error)
}

type Client struct {
httpClient *http.Client
httpClient doer
tlsConfig *tls.Config
userAgent string
baseURL string
token string
Expand Down Expand Up @@ -298,16 +303,11 @@
path = strings.Replace(c.baseURL, "https://", "wss://", 1) + path
}

var tlsConfig *tls.Config
transport := c.httpClient.Transport.(*http.Transport)
if transport != nil {
tlsConfig = transport.TLSClientConfig
}
c.log.Debugf("connecting to websocket: %s", path)
dialer := &websocket.Dialer{
Proxy: http.ProxyFromEnvironment,
HandshakeTimeout: 30 * time.Second,
TLSClientConfig: tlsConfig,
TLSClientConfig: c.tlsConfig,
}

dialerHeaders := http.Header{}
Expand Down
85 changes: 71 additions & 14 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,10 +589,10 @@ type Task struct {
User string
Status string
Node string
PID uint64 `json:",omitempty"`
PStart uint64 `json:",omitempty"`
Saved string `json:",omitempty"`
ExitStatus string `json:",omitempty"`
PID uint64 `json:",omitempty"`
PStart uint64 `json:",omitempty"`
Saved StringOrInt `json:",omitempty"`
ExitStatus string `json:",omitempty"`
IsCompleted bool
IsRunning bool
IsFailed bool
Expand Down Expand Up @@ -939,6 +939,7 @@ type FirewallSecurityGroup struct {
Comment string `json:"comment,omitempty"`
Rules []*FirewallRule `json:"rules,omitempty"`
}

type FirewallRule struct {
Type string `json:"type,omitempty"`
Action string `json:"action,omitempty"`
Expand All @@ -954,6 +955,8 @@ type FirewallRule struct {
Proto string `json:"proto,omitempty"`
Source string `json:"source,omitempty"`
Sport string `json:"sport,omitempty"`

MoveTo *int `json:"moveto,omitempty"` // Other fields will be ignored when used
}

func (r *FirewallRule) IsEnable() bool {
Expand All @@ -980,16 +983,16 @@ type FirewallNodeOption struct {
}

type FirewallVirtualMachineOption struct {
Enable bool `json:"enable,omitempty"`
Dhcp bool `json:"dhcp,omitempty"`
Ipfilter bool `json:"ipfilter,omitempty"`
LogLevelIn string `json:"log_level_in,omitempty"`
LogLevelOut string `json:"log_level_out,omitempty"`
Macfilter bool `json:"macfilter,omitempty"`
Ntp bool `json:"ntp,omitempty"`
PolicyIn string `json:"policy_in,omitempty"`
PolicyOut string `json:"policy_out,omitempty"`
Radv bool `json:"radv,omitempty"`
Enable *IntOrBool `json:"enable,omitempty"`
Dhcp *IntOrBool `json:"dhcp,omitempty"`
IpFilter *IntOrBool `json:"ipfilter,omitempty"`
LogLevelIn *string `json:"log_level_in,omitempty"`
LogLevelOut *string `json:"log_level_out,omitempty"`
MacFilter *IntOrBool `json:"macfilter,omitempty"`
Ndp *IntOrBool `json:"ndp,omitempty"`
PolicyIn *string `json:"policy_in,omitempty"`
PolicyOut *string `json:"policy_out,omitempty"`
Radv *IntOrBool `json:"radv,omitempty"`
}

type Snapshot struct {
Expand Down Expand Up @@ -1476,3 +1479,57 @@ type VzdumpConfig struct {
IPConfig8 string `json:"ipconfig8,omitempty"`
IPConfig9 string `json:"ipconfig9,omitempty"`
}

type (
HAType string
HAResourceState string
HAResourceType string
)

const (
HATypeGroup = HAType("group")

HAResourceStateStarted = HAResourceState("started")
HAResourceStateStopped = HAResourceState("stopped")
HAResourceStateEnabled = HAResourceState("enabled")
HAResourceStateDisabled = HAResourceState("disabled")
HAResourceStateIgnored = HAResourceState("ignored")

HAResourceTypeVm = HAResourceType("vm")
)

type HANodes struct {
Node string
Priority *uint
}

type HAGroupConfiguration struct {
Group string
HaNodes []HANodes
Comment *string
NoFailback *IntOrBool
Restricted *IntOrBool
}

type SID struct {
Type HAResourceType
ID int
}

type haResource struct {
Group string `json:"group"`
Sid string `json:"sid"`
State HAResourceState `json:"state"`
Comment string `json:"comment"`
MaxRestart uint `json:"max_restart"`
MaxRelocate uint `json:"max_relocate"`
}

type HAResource struct {
ID int `json:"sid"`
Group *string `json:"group"`
Comment *string `json:"comment,omitempty"`
MaxRelocate *uint `json:"max_relocate,omitempty"`
MaxRestart *uint `json:"max_restart,omitempty"`
State *HAResourceState `json:"state,omitempty"`
}
5 changes: 5 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package proxmox

func AsPtr[T any](input T) *T {
return &input
}
Loading
Loading