Skip to content

Commit 0a38381

Browse files
query DEP names (#128)
1 parent 7f0765b commit 0a38381

File tree

20 files changed

+778
-20
lines changed

20 files changed

+778
-20
lines changed

cmd/depserver/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/micromdm/nanodep/client"
1414
dephttp "github.com/micromdm/nanodep/http"
1515
"github.com/micromdm/nanodep/http/api"
16+
"github.com/micromdm/nanodep/http/apinext"
1617
"github.com/micromdm/nanodep/log/caller"
1718
"github.com/micromdm/nanodep/log/slog"
1819
"github.com/micromdm/nanodep/proxy"
@@ -102,6 +103,10 @@ func main() {
102103
assignerMux.Handle("PUT", api.StoreAssignerProfileHandler(storage, logger.With("handler", "store-assigner-profile")))
103104
handleStrippedAPI(assignerMux, endpointAssigner)
104105

106+
namesMux := dephttp.NewMethodMux()
107+
namesMux.Handle("GET", apinext.NewQueryDEPNamesHandler(storage, logger.With("handler", "query-dep-names")))
108+
handleStrippedAPI(namesMux, "/v1/dep_names")
109+
105110
handleStrippedAPI(api.NewBypassCodeHandler(), endpointALBC)
106111

107112
handleStrippedAPI(

docs/openapi.yaml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,52 @@ paths:
1919
version:
2020
type: string
2121
example: "v0.1.0"
22+
/v1/dep_names:
23+
get:
24+
description: Query DEP names.
25+
parameters:
26+
- in: query
27+
name: dep_name
28+
schema:
29+
type: array
30+
items:
31+
type: string
32+
- in: query
33+
name: limit
34+
schema:
35+
type: integer
36+
example: 20
37+
default: 100
38+
- in: query
39+
name: offset
40+
schema:
41+
type: integer
42+
- in: query
43+
name: cursor
44+
schema:
45+
type: string
46+
example: afcadc29a704
47+
security:
48+
- basicAuth: []
49+
responses:
50+
'200':
51+
description: Returns DEP name query results.
52+
content:
53+
application/json:
54+
schema:
55+
$ref: '#/components/schemas/DEPNamesQueryResponse'
56+
'400':
57+
description: Problem with the provided API query parameters.
58+
content:
59+
application/json:
60+
schema:
61+
$ref: '#/components/schemas/ErrorResponse'
62+
'500':
63+
description: Server error querying DEP names.
64+
content:
65+
application/json:
66+
schema:
67+
$ref: '#/components/schemas/ErrorResponse'
2268
/v1/assigner/{name}:
2369
get:
2470
description: Return the assigner profile UUID for the given DEP name.
@@ -391,6 +437,26 @@ components:
391437
format: url
392438
example: "http://127.0.0.1:8080/"
393439
description: The base URL of the Apple Device Assignment Services server to call out to. Typically only overridden when talking to another DEP server such as the `depsim` simulator.
440+
DEPNamesQueryResponse:
441+
type: object
442+
properties:
443+
dep_names:
444+
type: array
445+
items:
446+
type: string
447+
next_cursor:
448+
description: For storage backends that support cursor-based pagination this will contain the next cursor value.
449+
type: string
450+
ErrorResponse:
451+
type: object
452+
description: Error response.
453+
required:
454+
- error
455+
properties:
456+
error:
457+
type: string
458+
description: Error string.
459+
example: The sun is shining.
394460
OAuth1Tokens:
395461
type: object
396462
properties:

docs/operations-guide.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,24 @@ A brief overview of the endpoints is provided here. For detailed API semantics p
133133

134134
Returns a JSON response with the version of the running NanoDEP server.
135135

136+
#### DEP name query
137+
138+
* Endpoint: `GET /v1/dep_names`
139+
140+
The `/v1/dep_names` endpoint queries and returns DEP names. The DEP names need to have an upstaged (uploaded) DEP PKI operation to be considered query-able. Optional parameters are any specific `dep_name` parameters. Depending on the storage backend `offset` and `limit` or `cursor` parameters may be provided. For example:
141+
142+
`http://[::1]9001/v1/dep_names?dep_name=myMDMserver&dep_name=myMDMserver2&limit=2&offset=3`
143+
144+
Should return something like (if only `myMDMServer2` was query-able):
145+
146+
```json
147+
{
148+
"dep_names": [
149+
"myMDMserver2"
150+
]
151+
}
152+
```
153+
136154
#### Token PKI
137155

138156
* Endpoint: `GET, PUT /v1/tokenpki/{name}`

http/apinext/api.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Package apinext implements HTTP handlers for the NanoDEP API.
2+
// It exists to break the circular dependency between the storage and api packages.
3+
package apinext
4+
5+
import (
6+
"encoding/json"
7+
"net/http"
8+
9+
"github.com/micromdm/nanolib/log"
10+
)
11+
12+
// writeJSON encodes v to JSON writing to w using the HTTP status of header.
13+
// An error during encoding is logged to logger if it is not nil.
14+
// If header is 0 then none will be written to w (which defaults to 200).
15+
// Nothing will be encoded nor written to w if v is nil.
16+
func writeJSON(w http.ResponseWriter, v interface{}, header int, logger log.Logger) {
17+
w.Header().Set("Content-type", "application/json")
18+
19+
if header > 0 {
20+
w.WriteHeader(header)
21+
}
22+
23+
if v == nil {
24+
return
25+
}
26+
27+
enc := json.NewEncoder(w)
28+
enc.SetIndent("", "\t")
29+
err := enc.Encode(v)
30+
if err != nil && logger != nil {
31+
logger.Info("msg", "encoding json", "err", err)
32+
}
33+
}
34+
35+
// logAndWriteJSONError logs msg and err to logger as well as writes err to w as JSON.
36+
// If header is 0 it will default to 500.
37+
func logAndWriteJSONError(logger log.Logger, w http.ResponseWriter, msg string, err error, header int) {
38+
if logger != nil {
39+
logger.Info("msg", msg, "err", err)
40+
}
41+
42+
errStr := "<nil error>"
43+
if err != nil {
44+
errStr = err.Error()
45+
}
46+
47+
out := &ErrorResponseJson{Error: errStr}
48+
49+
if header < 1 {
50+
header = 500
51+
}
52+
53+
writeJSON(w, out, header, logger)
54+
}

http/apinext/depnames.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package apinext
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"strconv"
7+
8+
"github.com/micromdm/nanodep/storage"
9+
10+
"github.com/micromdm/nanolib/log"
11+
"github.com/micromdm/nanolib/log/ctxlog"
12+
)
13+
14+
// NewQueryDEPNamesHandler returns a handler that queries DEP names.
15+
func NewQueryDEPNamesHandler(store storage.DEPNamesQuery, logger log.Logger) http.HandlerFunc {
16+
return func(w http.ResponseWriter, r *http.Request) {
17+
p := new(storage.Pagination)
18+
19+
logger := ctxlog.Logger(r.Context(), logger)
20+
21+
var err error
22+
// extract and set pagination limit
23+
if limitRaw := r.URL.Query().Get("limit"); limitRaw != "" {
24+
limit, err := strconv.Atoi(limitRaw)
25+
if err != nil {
26+
logAndWriteJSONError(logger, w, "converting limit param", err, http.StatusBadRequest)
27+
return
28+
}
29+
30+
p.Limit = &limit
31+
}
32+
33+
// extract and set pagination offset
34+
if offsetRaw := r.URL.Query().Get("offset"); offsetRaw != "" {
35+
offset, err := strconv.Atoi(offsetRaw)
36+
if err != nil {
37+
logAndWriteJSONError(logger, w, "converting offset param", err, http.StatusBadRequest)
38+
return
39+
}
40+
41+
p.Offset = &offset
42+
}
43+
44+
// extract and set pagination cursor
45+
if cursorRaw := r.URL.Query().Get("cursor"); cursorRaw != "" {
46+
p.Cursor = &cursorRaw
47+
}
48+
49+
// assemble the query request
50+
q := &storage.DEPNamesQueryRequest{
51+
Filter: &storage.DEPNamesQueryFilter{
52+
DEPNames: r.URL.Query()["dep_name"],
53+
},
54+
Pagination: p,
55+
}
56+
57+
// perform query
58+
ret, err := store.QueryDEPNames(r.Context(), q)
59+
if err != nil {
60+
logAndWriteJSONError(logger, w, "querying DEP names", err, 0)
61+
return
62+
}
63+
64+
// log the success
65+
logger.Debug("msg", fmt.Sprintf("queried DEP names: %d", len(ret.DEPNames)))
66+
67+
// output the return
68+
writeJSON(w, ret, http.StatusOK, logger)
69+
}
70+
}

http/apinext/generate.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package apinext
2+
3+
//go:generate oa2js -o ErrorResponse.json ../../docs/openapi.yaml ErrorResponse
4+
//go:generate go-jsonschema -p $GOPACKAGE --tags json --only-models --output schema.go ErrorResponse.json
5+
//go:generate rm -f ErrorResponse.json

http/apinext/schema.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

storage/depnames.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package storage
2+
3+
import "context"
4+
5+
// DEPNamesQueryFilter is the filter parameters for querying DEP names.
6+
type DEPNamesQueryFilter struct {
7+
// DEPNames specifies which DEP names to query for.
8+
// DEP names in this list which exists are returned.
9+
DEPNames []string `json:"dep_names"`
10+
}
11+
12+
// DEPNamesQueryRequest is the parameters for querying DEP names.
13+
type DEPNamesQueryRequest struct {
14+
Filter *DEPNamesQueryFilter `json:"filter,omitempty"`
15+
Pagination *Pagination `json:"pagination,omitempty"`
16+
}
17+
18+
// DEPNamesQueryResult is the resulting paginated of the DEP names query.
19+
type DEPNamesQueryResult struct {
20+
DEPNames []string `json:"dep_names"`
21+
22+
PaginationNextCursor
23+
}
24+
25+
type DEPNamesQuery interface {
26+
// QueryDEPNames queries and returns DEP names.
27+
QueryDEPNames(ctx context.Context, req *DEPNamesQueryRequest) (*DEPNamesQueryResult, error)
28+
}

storage/file/file.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,8 @@ func (s *FileStorage) retrieveTokenPKIExtn(name, extn string) ([]byte, []byte, e
235235
}
236236
return certBytes, keyBytes, err
237237
}
238+
239+
// QueryDEPNames queries and returns DEP names.
240+
func (s *FileStorage) QueryDEPNames(ctx context.Context, req *storage.DEPNamesQueryRequest) (*storage.DEPNamesQueryResult, error) {
241+
return nil, errors.New("not implemented")
242+
}

storage/file/file_test.go

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)