diff --git a/cluster.go b/cluster.go index 244e701..3eb512e 100644 --- a/cluster.go +++ b/cluster.go @@ -2,6 +2,7 @@ package proxmox import ( "context" + "fmt" "net/url" "strconv" "strings" @@ -32,6 +33,21 @@ func (cl *Cluster) NextID(ctx context.Context) (int, error) { return strconv.Atoi(ret) } +// CheckID checks if the given vmid is free. +// CheckID calls the /cluster/nextid endpoint with the "vmid" parameter. +// The API documentation describes the check as: "Pass a VMID to assert that its free (at time of check)." +// Returns true if the vmid is free, false otherwise. +func (cl *Cluster) CheckID(ctx context.Context, vmid int) (bool, error) { + var ret string + err := cl.client.Get(ctx, fmt.Sprintf("/cluster/nextid?vmid=%d", vmid), ret) + if err != nil && strings.Contains(err.Error(), fmt.Sprintf("VM %d already exists", vmid)) { + return false, nil + } else if err != nil { + return false, err + } + return true, nil +} + // Resources retrieves a summary list of all resources in the cluster. // It calls /cluster/resources api v2 endpoint with an optional "type" parameter // to filter searched values. diff --git a/cluster_test.go b/cluster_test.go index 717eda3..72abb80 100644 --- a/cluster_test.go +++ b/cluster_test.go @@ -37,6 +37,22 @@ func TestNextID(t *testing.T) { assert.Equal(t, 100, nextid) } +func TestCheckID(t *testing.T) { + mocks.On(mockConfig) + defer mocks.Off() + client := mockClient() + ctx := context.Background() + + cluster, err := client.Cluster(ctx) + assert.Nil(t, err) + checkIDFree, err := cluster.CheckID(ctx, 100) + assert.Nil(t, err) + assert.Equal(t, true, checkIDFree) + checkIDTaken, err := cluster.CheckID(ctx, 200) + assert.Nil(t, err) + assert.Equal(t, false, checkIDTaken) +} + func TestCluster_Resources(t *testing.T) { mocks.On(mockConfig) defer mocks.Off() diff --git a/tests/mocks/pve7x/cluster.go b/tests/mocks/pve7x/cluster.go index 52542ef..00e6861 100644 --- a/tests/mocks/pve7x/cluster.go +++ b/tests/mocks/pve7x/cluster.go @@ -7,10 +7,22 @@ import ( func cluster() { gock.New(config.C.URI). - Get("/cluster/nextid"). + Get("/cluster/nextid$"). + Reply(200). + JSON(`{"data": "100"}`) + + gock.New(config.C.URI). + Get("/cluster/nextid$"). + MatchParam("vmid", "100"). Reply(200). JSON(`{"data": "100"}`) + gock.New(config.C.URI). + Get("/cluster/nextid"). + MatchParam("vmid", "200"). + Reply(400). + JSON(`{"errors":{"vmid":"VM 200 already exists"},"data":null}`) + gock.New(config.C.URI). Get("/cluster/status"). Reply(200).