Skip to content

Commit d9af5a9

Browse files
Implement GET /cvds/{group}/{name} endpoint
1 parent 33b07be commit d9af5a9

4 files changed

Lines changed: 82 additions & 17 deletions

File tree

frontend/src/host_orchestrator/orchestrator/controller.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func (c *Controller) AddRoutes(router *mux.Router) {
6868
httpHandler(newCreateCVDHandler(c.Config, c.OperationManager, c.UserArtifactsManager))).Methods("POST")
6969
router.Handle("/cvds", httpHandler(&listCVDsHandlerAll{Config: c.Config})).Methods("GET")
7070
router.Handle("/cvds/{group}", httpHandler(&listCVDsHandler{Config: c.Config})).Methods("GET")
71+
router.Handle("/cvds/{group}/{name}", httpHandler(&listCVDsHandler{Config: c.Config})).Methods("GET")
7172
router.PathPrefix("/cvds/{group}/{name}/logs").Handler(&getCVDLogsHandler{Config: c.Config}).Methods("GET")
7273
router.Handle("/cvds/{group}/:start",
7374
httpHandler(newExecCVDGroupCommandHandler(c.Config, c.OperationManager, &startCvdCommand{}))).Methods("POST")
@@ -296,6 +297,7 @@ func (h *listCVDsHandler) Handle(r *http.Request) (interface{}, error) {
296297
vars := mux.Vars(r)
297298
opts := ListCVDsActionOpts{
298299
Group: vars["group"],
300+
Name: vars["name"],
299301
Paths: h.Config.Paths,
300302
ExecContext: exec.CommandContext,
301303
}

frontend/src/host_orchestrator/orchestrator/controller_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ func TestGetCVDLogsIsHandled(t *testing.T) {
6666
}
6767
}
6868

69+
func TestGetCVDIsHandled(t *testing.T) {
70+
rr := httptest.NewRecorder()
71+
req, err := http.NewRequest("GET", "/cvds/foo/bar", nil)
72+
if err != nil {
73+
t.Fatal(err)
74+
}
75+
controller := Controller{}
76+
77+
makeRequest(rr, req, &controller)
78+
79+
if rr.Code == http.StatusNotFound && rr.Body.String() == pageNotFoundErrMsg {
80+
t.Errorf("request was not handled. This failure implies an API breaking change.")
81+
}
82+
}
83+
6984
func TestGetOperationIsHandled(t *testing.T) {
7085
rr := httptest.NewRecorder()
7186
req, err := http.NewRequest("GET", "/operations/foo", nil)

frontend/src/host_orchestrator/orchestrator/listcvdsaction.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,22 @@ import (
2525

2626
type ListCVDsActionOpts struct {
2727
Group string
28+
Name string
2829
Paths IMPaths
2930
ExecContext exec.ExecContext
3031
}
3132

3233
type ListCVDsAction struct {
3334
group string
35+
name string
3436
paths IMPaths
3537
cvdCLI *cvd.CLI
3638
}
3739

3840
func NewListCVDsAction(opts ListCVDsActionOpts) *ListCVDsAction {
3941
return &ListCVDsAction{
4042
group: opts.Group,
43+
name: opts.Name,
4144
paths: opts.Paths,
4245
cvdCLI: cvd.NewCLI(opts.ExecContext),
4346
}
@@ -56,8 +59,19 @@ func (a *ListCVDsAction) Run() (*apiv1.ListCVDsResponse, error) {
5659
groups = []*cvd.Group{g}
5760
}
5861
cvds := []*apiv1.CVD{}
59-
for _, g := range groups {
60-
cvds = append(cvds, CvdGroupToAPIObject(g)...)
62+
if a.name != "" {
63+
if len(groups) == 0 {
64+
return nil, operator.NewNotFoundError(fmt.Sprintf("CVD %q not found", a.name), nil)
65+
}
66+
found, ins := findInstance(groups[0], a.name)
67+
if !found {
68+
return nil, operator.NewNotFoundError(fmt.Sprintf("CVD %q not found in group %q", a.name, a.group), nil)
69+
}
70+
cvds = []*apiv1.CVD{CvdInstanceToAPIObject(ins, a.group)}
71+
} else {
72+
for _, g := range groups {
73+
cvds = append(cvds, CvdGroupToAPIObject(g)...)
74+
}
6175
}
6276
return &apiv1.ListCVDsResponse{CVDs: cvds}, nil
6377
}

frontend/src/host_orchestrator/orchestrator/listcvdsaction_test.go

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,29 +105,63 @@ func TestListCVDsSucceeds(t *testing.T) {
105105
},
106106
}
107107
var tests = []struct {
108-
group string
109-
want *apiv1.ListCVDsResponse
108+
nameDesc string
109+
group string
110+
name string
111+
want *apiv1.ListCVDsResponse
112+
wantErr bool
110113
}{
111114
{
112-
group: "",
113-
want: &apiv1.ListCVDsResponse{CVDs: cvds},
115+
nameDesc: "list all",
116+
group: "",
117+
name: "",
118+
want: &apiv1.ListCVDsResponse{CVDs: cvds},
114119
},
115120
{
116-
group: "foo",
117-
want: &apiv1.ListCVDsResponse{CVDs: []*apiv1.CVD{cvds[0]}},
121+
nameDesc: "list group foo",
122+
group: "foo",
123+
name: "",
124+
want: &apiv1.ListCVDsResponse{CVDs: []*apiv1.CVD{cvds[0]}},
125+
},
126+
{
127+
nameDesc: "get cvd 1 in group foo",
128+
group: "foo",
129+
name: "1",
130+
want: &apiv1.ListCVDsResponse{CVDs: []*apiv1.CVD{cvds[0]}},
131+
},
132+
{
133+
nameDesc: "get cvd 2 in group foo (not found)",
134+
group: "foo",
135+
name: "2",
136+
wantErr: true,
137+
},
138+
{
139+
nameDesc: "get cvd 1 in non-existent group (not found)",
140+
group: "baz",
141+
name: "1",
142+
wantErr: true,
118143
},
119144
}
120145
for _, test := range tests {
121-
opts := ListCVDsActionOpts{
122-
Group: test.group,
123-
ExecContext: execContext,
124-
}
125-
action := NewListCVDsAction(opts)
146+
t.Run(test.nameDesc, func(t *testing.T) {
147+
opts := ListCVDsActionOpts{
148+
Group: test.group,
149+
Name: test.name,
150+
ExecContext: execContext,
151+
}
152+
action := NewListCVDsAction(opts)
126153

127-
res, _ := action.Run()
154+
res, err := action.Run()
128155

129-
if diff := cmp.Diff(test.want, res); diff != "" {
130-
t.Errorf("response mismatch (-want +got):\n%s", diff)
131-
}
156+
if (err != nil) != test.wantErr {
157+
t.Errorf("wantErr %v, got %v", test.wantErr, err)
158+
}
159+
if test.wantErr {
160+
return
161+
}
162+
if diff := cmp.Diff(test.want, res); diff != "" {
163+
t.Errorf("response mismatch (-want +got):\n%s", diff)
164+
}
165+
})
132166
}
133167
}

0 commit comments

Comments
 (0)