Skip to content

Commit ca62b68

Browse files
kwadhwa-sourcecursoragentDO-rrao
authored
MDROP-21: add doctl support for microdroplets (#1890)
Introduces the `doctl compute microdroplet` command tree, aligned with the godo MicroDroplet support released in v1.201.0: - `microdroplet list|get|create|delete` for MicroDroplet instances. - `microdroplet pause|resume` calling the dedicated godo Pause/Resume actions (POST .../instances/{id}/pause and .../resume). - `microdroplet checkpoints` (alias `cp`) calling godo ListCheckpoints. - `microdroplet image list|get|create|delete` for MicroDroplet images. Also adds a `do.MicroDropletsService` / `do.MicroDropletImagesService` wrapper layer with mockery-generated mocks, and bumps godo to v1.201.0 to pick up the microdroplet client. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Radhika Rao <rrao@digitalocean.com>
1 parent dc3d425 commit ca62b68

15 files changed

Lines changed: 1786 additions & 10 deletions

commands/command_config.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,18 @@ type CmdConfig struct {
4141
componentBuilderFactory builder.ComponentBuilderFactory
4242

4343
// services
44-
Keys func() do.KeysService
45-
Sizes func() do.SizesService
46-
Regions func() do.RegionsService
47-
Images func() do.ImagesService
48-
ImageActions func() do.ImageActionsService
49-
LoadBalancers func() do.LoadBalancersService
50-
ReservedIPs func() do.ReservedIPsService
51-
ReservedIPActions func() do.ReservedIPActionsService
52-
ReservedIPv6s func() do.ReservedIPv6sService
53-
BYOIPPrefixes func() do.BYOIPPrefixsService
44+
Keys func() do.KeysService
45+
Sizes func() do.SizesService
46+
Regions func() do.RegionsService
47+
Images func() do.ImagesService
48+
ImageActions func() do.ImageActionsService
49+
LoadBalancers func() do.LoadBalancersService
50+
MicroDroplets func() do.MicroDropletsService
51+
MicroDropletImages func() do.MicroDropletImagesService
52+
ReservedIPs func() do.ReservedIPsService
53+
ReservedIPActions func() do.ReservedIPActionsService
54+
ReservedIPv6s func() do.ReservedIPv6sService
55+
BYOIPPrefixes func() do.BYOIPPrefixsService
5456

5557
Droplets func() do.DropletsService
5658
DropletActions func() do.DropletActionsService
@@ -164,6 +166,10 @@ func NewCmdConfig(ns string, dc doctl.Config, out io.Writer, args []string, init
164166
}
165167
c.Nfs = func() do.NfsService { return do.NewNfsService(godoClient) }
166168
c.NfsActions = func() do.NfsActionsService { return do.NewNfsActionsService(godoClient) }
169+
c.MicroDroplets = func() do.MicroDropletsService { return do.NewMicroDropletsService(godoClient) }
170+
c.MicroDropletImages = func() do.MicroDropletImagesService {
171+
return do.NewMicroDropletImagesService(godoClient)
172+
}
167173
c.Security = func() do.SecurityService { return do.NewSecurityService(godoClient) }
168174
c.Secrets = func() do.SecretsService { return do.NewSecretsService(godoClient) }
169175
return nil

commands/commands_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ type tcMocks struct {
296296
inference *domocks.MockInferenceService
297297
nfs *domocks.MockNfsService
298298
nfsActions *domocks.MockNfsActionsService
299+
microDroplets *domocks.MockMicroDropletsService
300+
microDropletImages *domocks.MockMicroDropletImagesService
299301
security *domocks.MockSecurityService
300302
secrets *domocks.MockSecretsService
301303
vectorDBs *domocks.MockVectorDBsService
@@ -358,6 +360,8 @@ func withTestClient(t *testing.T, tFn testFn) {
358360
inference: domocks.NewMockInferenceService(ctrl),
359361
nfs: domocks.NewMockNfsService(ctrl),
360362
nfsActions: domocks.NewMockNfsActionsService(ctrl),
363+
microDroplets: domocks.NewMockMicroDropletsService(ctrl),
364+
microDropletImages: domocks.NewMockMicroDropletImagesService(ctrl),
361365
security: domocks.NewMockSecurityService(ctrl),
362366
secrets: domocks.NewMockSecretsService(ctrl),
363367
vectorDBs: domocks.NewMockVectorDBsService(ctrl),
@@ -428,6 +432,8 @@ func withTestClient(t *testing.T, tFn testFn) {
428432
Inference: func() do.InferenceService { return tm.inference },
429433
Nfs: func() do.NfsService { return tm.nfs },
430434
NfsActions: func() do.NfsActionsService { return tm.nfsActions },
435+
MicroDroplets: func() do.MicroDropletsService { return tm.microDroplets },
436+
MicroDropletImages: func() do.MicroDropletImagesService { return tm.microDropletImages },
431437
Security: func() do.SecurityService { return tm.security },
432438
Secrets: func() do.SecretsService { return tm.secrets },
433439
VectorDBs: func() do.VectorDBsService { return tm.vectorDBs },
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
Copyright 2025 The Doctl Authors All rights reserved.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package displayers
15+
16+
import (
17+
"io"
18+
19+
"github.com/digitalocean/doctl/do"
20+
)
21+
22+
type MicroDroplet struct {
23+
MicroDroplets do.MicroDroplets
24+
}
25+
26+
var _ Displayable = &MicroDroplet{}
27+
28+
func (m *MicroDroplet) JSON(out io.Writer) error {
29+
return writeJSON(m.MicroDroplets, out)
30+
}
31+
32+
func (m *MicroDroplet) Cols() []string {
33+
return []string{
34+
"ID", "Name", "Region", "State", "Size", "Networking", "Image", "Endpoint", "Created",
35+
}
36+
}
37+
38+
func (m *MicroDroplet) ColMap() map[string]string {
39+
return map[string]string{
40+
"ID": "ID",
41+
"Name": "Name",
42+
"Region": "Region",
43+
"State": "State",
44+
"Size": "Size",
45+
"Networking": "Networking",
46+
"Image": "Image",
47+
"Endpoint": "Endpoint",
48+
"Created": "Created At",
49+
}
50+
}
51+
52+
func (m *MicroDroplet) KV() []map[string]any {
53+
out := make([]map[string]any, 0, len(m.MicroDroplets))
54+
for _, md := range m.MicroDroplets {
55+
out = append(out, map[string]any{
56+
"ID": md.ID,
57+
"Name": md.Name,
58+
"Region": md.Region,
59+
"State": string(md.State),
60+
"Size": md.Size,
61+
"Networking": string(md.Networking),
62+
"Image": md.Image,
63+
"Endpoint": md.Endpoint,
64+
"Created": md.Created,
65+
})
66+
}
67+
return out
68+
}
69+
70+
type MicroDropletCheckpoint struct {
71+
Checkpoints do.MicroDropletCheckpoints
72+
}
73+
74+
var _ Displayable = &MicroDropletCheckpoint{}
75+
76+
func (c *MicroDropletCheckpoint) JSON(out io.Writer) error {
77+
return writeJSON(c.Checkpoints, out)
78+
}
79+
80+
func (c *MicroDropletCheckpoint) Cols() []string {
81+
return []string{
82+
"ID", "MicroDropletID", "Name", "Status", "MemoryBytes", "DiskBytes", "Created",
83+
}
84+
}
85+
86+
func (c *MicroDropletCheckpoint) ColMap() map[string]string {
87+
return map[string]string{
88+
"ID": "ID",
89+
"MicroDropletID": "MicroDroplet ID",
90+
"Name": "Name",
91+
"Status": "Status",
92+
"MemoryBytes": "Memory Bytes",
93+
"DiskBytes": "Disk Bytes",
94+
"Created": "Created At",
95+
}
96+
}
97+
98+
func (c *MicroDropletCheckpoint) KV() []map[string]any {
99+
out := make([]map[string]any, 0, len(c.Checkpoints))
100+
for _, cp := range c.Checkpoints {
101+
out = append(out, map[string]any{
102+
"ID": cp.ID,
103+
"MicroDropletID": cp.MicroDropletID,
104+
"Name": cp.Name,
105+
"Status": string(cp.Status),
106+
"MemoryBytes": cp.MemoryBytes,
107+
"DiskBytes": cp.DiskBytes,
108+
"Created": cp.Created,
109+
})
110+
}
111+
return out
112+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
Copyright 2025 The Doctl Authors All rights reserved.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package displayers
15+
16+
import (
17+
"io"
18+
19+
"github.com/digitalocean/doctl/do"
20+
)
21+
22+
type MicroDropletImage struct {
23+
Images do.MicroDropletImages
24+
}
25+
26+
var _ Displayable = &MicroDropletImage{}
27+
28+
func (i *MicroDropletImage) JSON(out io.Writer) error {
29+
return writeJSON(i.Images, out)
30+
}
31+
32+
func (i *MicroDropletImage) Cols() []string {
33+
return []string{"ID", "Name", "Source", "Status", "Created"}
34+
}
35+
36+
func (i *MicroDropletImage) ColMap() map[string]string {
37+
return map[string]string{
38+
"ID": "ID",
39+
"Name": "Name",
40+
"Source": "Source",
41+
"Status": "Status",
42+
"Created": "Created At",
43+
}
44+
}
45+
46+
func (i *MicroDropletImage) KV() []map[string]any {
47+
out := make([]map[string]any, 0, len(i.Images))
48+
for _, img := range i.Images {
49+
out = append(out, map[string]any{
50+
"ID": img.ID,
51+
"Name": img.Name,
52+
"Source": img.Source,
53+
"Status": string(img.Status),
54+
"Created": img.Created,
55+
})
56+
}
57+
return out
58+
}

commands/doit.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ func computeCmd() *Command {
219219
cmd.AddCommand(Droplet())
220220
cmd.AddCommand(DropletAutoscale())
221221
cmd.AddCommand(Domain())
222+
cmd.AddCommand(MicroDroplet())
222223
cmd.AddCommand(VPCNATGateway())
223224
cmd.AddCommand(Firewall())
224225
cmd.AddCommand(ReservedIP())

0 commit comments

Comments
 (0)