refactor blueprint service for HA (#348)

Cleanup blueprints by moving the service into its own package.

Closes #297
This commit is contained in:
Victor Vrantchan
2017-12-09 18:09:06 -05:00
committed by GitHub
parent 83ea8491aa
commit c87bca7116
26 changed files with 446 additions and 316 deletions

View File

@@ -148,7 +148,7 @@ func (cmd *applyCommand) applyBlueprint(args []string) error {
}
ctx := context.Background()
err = cmd.applysvc.ApplyBlueprint(ctx, &blpt)
err = cmd.blueprintsvc.ApplyBlueprint(ctx, &blpt)
if err != nil {
return err
}

View File

@@ -17,6 +17,7 @@ import (
"github.com/micromdm/micromdm/pkg/crypto"
"github.com/micromdm/micromdm/platform/api/server/list"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/profile"
)
@@ -232,7 +233,7 @@ func (cmd *getCommand) getBlueprints(args []string) error {
}
ctx := context.Background()
blueprints, err := cmd.list.GetBlueprints(ctx, list.GetBlueprintsOption{FilterName: *flBlueprintName})
blueprints, err := cmd.blueprintsvc.GetBlueprints(ctx, blueprint.GetBlueprintsOption{FilterName: *flBlueprintName})
if err != nil {
return err
}

BIN
cmd/mdmctl/mdmctl Executable file

Binary file not shown.

View File

@@ -18,7 +18,7 @@ func (cmd *removeCommand) removeBlueprints(args []string) error {
}
ctx := context.Background()
err := cmd.remove.RemoveBlueprints(ctx, strings.Split(*flBlueprintName, ","))
err := cmd.blueprintsvc.RemoveBlueprints(ctx, strings.Split(*flBlueprintName, ","))
if err != nil {
return err
}

View File

@@ -7,14 +7,16 @@ import (
"github.com/micromdm/micromdm/platform/api/server/apply"
"github.com/micromdm/micromdm/platform/api/server/list"
"github.com/micromdm/micromdm/platform/api/server/remove"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/profile"
)
type remoteServices struct {
profilesvc profile.Service
applysvc apply.Service
list list.Service
remove remove.Service
profilesvc profile.Service
blueprintsvc blueprint.Service
applysvc apply.Service
list list.Service
remove remove.Service
}
func setupClient(logger log.Logger) (*remoteServices, error) {
@@ -22,20 +24,28 @@ func setupClient(logger log.Logger) (*remoteServices, error) {
if err != nil {
return nil, err
}
applysvc, err := apply.NewClient(
cfg.ServerURL, logger, cfg.APIToken,
profilesvc, err := profile.NewHTTPClient(
cfg.ServerURL, cfg.APIToken, logger,
httptransport.SetClient(skipVerifyHTTPClient(cfg.SkipVerify)))
if err != nil {
return nil, err
}
profilesvc, err := profile.NewHTTPClient(
blueprintsvc, err := blueprint.NewHTTPClient(
cfg.ServerURL, cfg.APIToken, logger,
httptransport.SetClient(skipVerifyHTTPClient(cfg.SkipVerify)))
if err != nil {
return nil, err
}
applysvc, err := apply.NewClient(
cfg.ServerURL, logger, cfg.APIToken,
httptransport.SetClient(skipVerifyHTTPClient(cfg.SkipVerify)))
if err != nil {
return nil, err
}
listsvc, err := list.NewClient(
cfg.ServerURL, logger, cfg.APIToken,
httptransport.SetClient(skipVerifyHTTPClient(cfg.SkipVerify)))
@@ -51,9 +61,10 @@ func setupClient(logger log.Logger) (*remoteServices, error) {
}
return &remoteServices{
profilesvc: profilesvc,
applysvc: applysvc,
list: listsvc,
remove: rmsvc,
profilesvc: profilesvc,
blueprintsvc: blueprintsvc,
applysvc: applysvc,
list: listsvc,
remove: rmsvc,
}, nil
}

View File

@@ -49,6 +49,7 @@ import (
"github.com/micromdm/micromdm/platform/apns"
"github.com/micromdm/micromdm/platform/appstore"
"github.com/micromdm/micromdm/platform/blueprint"
blueprintbuiltin "github.com/micromdm/micromdm/platform/blueprint/builtin"
"github.com/micromdm/micromdm/platform/command"
"github.com/micromdm/micromdm/platform/config"
"github.com/micromdm/micromdm/platform/deptoken"
@@ -186,7 +187,7 @@ func serve(args []string) error {
stdlog.Fatalf("enrollment service: %s", sm.err)
}
bpDB, err := blueprint.NewDB(sm.db, sm.profileDB, userDB)
bpDB, err := blueprintbuiltin.NewDB(sm.db, sm.profileDB, userDB)
if err != nil {
stdlog.Fatal(err)
}
@@ -277,15 +278,21 @@ func serve(args []string) error {
profileEndpoints := profile.MakeServerEndpoints(profilesvc)
var blueprintsvc blueprint.Service
{
blueprintsvc = blueprint.New(bpDB)
}
blueprintEndpoints := blueprint.MakeServerEndpoints(blueprintsvc)
var listsvc list.Service
{
l := &list.ListService{
DEPClient: dc,
Devices: devDB,
Tokens: tokenDB,
Blueprints: bpDB,
Apps: appDB,
Users: userDB,
DEPClient: dc,
Devices: devDB,
Tokens: tokenDB,
Apps: appDB,
Users: userDB,
}
listsvc = l
@@ -301,7 +308,6 @@ func serve(args []string) error {
listEndpoints := list.Endpoints{
ListDevicesEndpoint: listDevicesEndpoint,
GetDEPTokensEndpoint: list.MakeGetDEPTokensEndpoint(listsvc),
GetBlueprintsEndpoint: list.MakeGetBlueprintsEndpoint(listsvc),
GetDEPAccountInfoEndpoint: list.MakeGetDEPAccountInfoEndpoint(listsvc),
GetDEPProfileEndpoint: list.MakeGetDEPProfileEndpoint(listsvc),
GetDEPDeviceEndpoint: list.MakeGetDEPDeviceDetailsEndpoint(listsvc),
@@ -313,7 +319,6 @@ func serve(args []string) error {
{
l := &apply.ApplyService{
DEPClient: dc,
Blueprints: bpDB,
Tokens: tokenDB,
Apps: appDB,
Users: userDB,
@@ -325,11 +330,6 @@ func serve(args []string) error {
}
}
var applyBlueprintEndpoint endpoint.Endpoint
{
applyBlueprintEndpoint = apply.MakeApplyBlueprintEndpoint(applysvc)
}
var defineDEPProfileEndpoint endpoint.Endpoint
{
defineDEPProfileEndpoint = apply.MakeDefineDEPProfile(applysvc)
@@ -346,7 +346,6 @@ func serve(args []string) error {
}
applyEndpoints := apply.Endpoints{
ApplyBlueprintEndpoint: applyBlueprintEndpoint,
ApplyDEPTokensEndpoint: apply.MakeApplyDEPTokensEndpoint(applysvc),
DefineDEPProfileEndpoint: defineDEPProfileEndpoint,
AppUploadEndpoint: appUploadEndpoint,
@@ -358,7 +357,7 @@ func serve(args []string) error {
listAPIHandlers := list.MakeHTTPHandlers(ctx, listEndpoints, connectOpts...)
rmsvc := &remove.RemoveService{Blueprints: bpDB, RemoveService: removeService}
rmsvc := &remove.RemoveService{RemoveService: removeService}
removeAPIHandlers := remove.MakeHTTPHandlers(ctx, remove.MakeEndpoints(rmsvc), connectOpts...)
connectHandlers := connect.MakeHTTPHandlers(ctx, connectEndpoints, connectOpts...)
@@ -378,10 +377,12 @@ func serve(args []string) error {
})
profilesHandler := profile.MakeHTTPHandler(profileEndpoints, logger)
blueprintsHandler := blueprint.MakeHTTPHandler(blueprintEndpoints, logger)
// API commands. Only handled if the user provides an api key.
if *flAPIKey != "" {
r.Handle("/v1/profiles", apiAuthMiddleware(*flAPIKey, profilesHandler))
r.Handle("/v1/blueprints", apiAuthMiddleware(*flAPIKey, blueprintsHandler))
r.Handle("/push/{udid}", apiAuthMiddleware(*flAPIKey, pushHandlers.PushHandler))
r.Handle("/v1/commands", apiAuthMiddleware(*flAPIKey, commandHandlers.NewCommandHandler)).Methods("POST")
r.Handle("/v1/devices", apiAuthMiddleware(*flAPIKey, listAPIHandlers.ListDevicesHandler)).Methods("GET")
@@ -389,9 +390,6 @@ func serve(args []string) error {
r.Handle("/v1/devices/{udid}/unblock", apiAuthMiddleware(*flAPIKey, removeAPIHandlers.UnblockDeviceHandler)).Methods("POST")
r.Handle("/v1/dep-tokens", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetDEPTokensHandler)).Methods("GET")
r.Handle("/v1/dep-tokens", apiAuthMiddleware(*flAPIKey, applyAPIHandlers.DEPTokensHandler)).Methods("PUT")
r.Handle("/v1/blueprints", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetBlueprintsHandler)).Methods("GET")
r.Handle("/v1/blueprints", apiAuthMiddleware(*flAPIKey, applyAPIHandlers.BlueprintHandler)).Methods("PUT")
r.Handle("/v1/blueprints", apiAuthMiddleware(*flAPIKey, removeAPIHandlers.BlueprintHandler)).Methods("DELETE")
r.Handle("/v1/dep/devices", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetDEPDeviceDetailsHandler)).Methods("GET")
r.Handle("/v1/dep/account", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetDEPAccountInfoHandler)).Methods("GET")
r.Handle("/v1/dep/profiles", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetDEPProfileHandler)).Methods("GET")

View File

@@ -16,16 +16,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
return nil, err
}
var applyBlueprintEndpoint endpoint.Endpoint
{
applyBlueprintEndpoint = httptransport.NewClient(
"PUT",
copyURL(u, "/v1/blueprints"),
encodeRequestWithToken(token, EncodeHTTPGenericRequest),
DecodeBlueprintResponse,
opts...,
).Endpoint()
}
var applyDEPTokensEndpoint endpoint.Endpoint
{
applyDEPTokensEndpoint = httptransport.NewClient(
@@ -82,7 +72,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
}
return Endpoints{
ApplyBlueprintEndpoint: applyBlueprintEndpoint,
ApplyDEPTokensEndpoint: applyDEPTokensEndpoint,
DefineDEPProfileEndpoint: defineDEPProfileEndpoint,
AppUploadEndpoint: uploadAppEndpoint,

View File

@@ -7,12 +7,10 @@ import (
"github.com/go-kit/kit/endpoint"
"github.com/micromdm/dep"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/user"
)
type Endpoints struct {
ApplyBlueprintEndpoint endpoint.Endpoint
ApplyDEPTokensEndpoint endpoint.Endpoint
DefineDEPProfileEndpoint endpoint.Endpoint
AppUploadEndpoint endpoint.Endpoint
@@ -67,15 +65,6 @@ func (e Endpoints) DefineDEPProfile(ctx context.Context, p *dep.Profile) (*dep.P
return response.ProfileResponse, response.Err
}
func (e Endpoints) ApplyBlueprint(ctx context.Context, bp *blueprint.Blueprint) error {
request := blueprintRequest{Blueprint: bp}
resp, err := e.ApplyBlueprintEndpoint(ctx, request)
if err != nil {
return err
}
return resp.(blueprintResponse).Err
}
func (e Endpoints) ApplyDEPToken(ctx context.Context, P7MContent []byte) error {
req := depTokensRequest{P7MContent: P7MContent}
resp, err := e.ApplyDEPTokensEndpoint(ctx, req)
@@ -85,16 +74,6 @@ func (e Endpoints) ApplyDEPToken(ctx context.Context, P7MContent []byte) error {
return resp.(depTokensResponse).Err
}
func MakeApplyBlueprintEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(blueprintRequest)
err = svc.ApplyBlueprint(ctx, req.Blueprint)
return blueprintResponse{
Err: err,
}, nil
}
}
func MakeApplyDEPTokensEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(depTokensRequest)
@@ -161,16 +140,6 @@ type appUploadResponse struct {
func (r appUploadResponse) error() error { return r.Err }
type blueprintRequest struct {
Blueprint *blueprint.Blueprint `json:"blueprint"`
}
type blueprintResponse struct {
Err error `json:"err,omitempty"`
}
func (r blueprintResponse) error() error { return r.Err }
type depTokensRequest struct {
P7MContent []byte `json:"p7m_content"`
}

View File

@@ -17,7 +17,6 @@ import (
"github.com/pkg/errors"
"github.com/micromdm/micromdm/platform/appstore"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/deptoken"
"github.com/micromdm/micromdm/platform/pubsub"
"github.com/micromdm/micromdm/platform/remove"
@@ -25,7 +24,6 @@ import (
)
type Service interface {
ApplyBlueprint(ctx context.Context, bp *blueprint.Blueprint) error
ApplyDEPToken(ctx context.Context, P7MContent []byte) error
UploadApp(ctx context.Context, manifestName string, manifest io.Reader, pkgName string, pkg io.Reader) error
ApplyUser(ctx context.Context, u user.User) (*user.User, error)
@@ -37,10 +35,9 @@ type ApplyService struct {
mtx sync.RWMutex
DEPClient dep.Client
Blueprints *blueprint.DB
Tokens *deptoken.DB
Apps appstore.AppStore
Users *user.DB
Tokens *deptoken.DB
Apps appstore.AppStore
Users *user.DB
*remove.RemoveService
}
@@ -105,10 +102,6 @@ func (svc *ApplyService) WatchTokenUpdates(pubsub pubsub.Subscriber) error {
return nil
}
func (svc *ApplyService) ApplyBlueprint(ctx context.Context, bp *blueprint.Blueprint) error {
return svc.Blueprints.Save(bp)
}
// unwrapSMIME removes the S/MIME-like wrapper around raw CMS/PKCS7 data
func unwrapSMIME(smime []byte) ([]byte, error) {
tr := textproto.NewReader(bufio.NewReader(bytes.NewReader(smime)))

View File

@@ -16,7 +16,6 @@ import (
)
type HTTPHandlers struct {
BlueprintHandler http.Handler
DEPTokensHandler http.Handler
DefineDEPProfileHandler http.Handler
AppUploadHandler http.Handler
@@ -26,12 +25,6 @@ type HTTPHandlers struct {
func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptransport.ServerOption) HTTPHandlers {
h := HTTPHandlers{
BlueprintHandler: httptransport.NewServer(
endpoints.ApplyBlueprintEndpoint,
decodeBlueprintRequest,
encodeResponse,
opts...,
),
DEPTokensHandler: httptransport.NewServer(
endpoints.ApplyDEPTokensEndpoint,
decodeDEPTokensRequest,
@@ -86,14 +79,6 @@ func decodeDEPTokensRequest(ctx context.Context, r *http.Request) (interface{},
return req, nil
}
func decodeBlueprintRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var bpReq blueprintRequest
if err := json.NewDecoder(r.Body).Decode(&bpReq); err != nil {
return nil, err
}
return bpReq, nil
}
func decodeDEPProfileRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req depProfileRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -221,15 +206,6 @@ func encodeBlockDeviceRequest(_ context.Context, r *http.Request, request interf
return nil
}
func DecodeBlueprintResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp blueprintResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func DecodeDEPTokensResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)

View File

@@ -36,16 +36,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
opts...,
).Endpoint()
}
var getBlueprintsEndpoint endpoint.Endpoint
{
getBlueprintsEndpoint = httptransport.NewClient(
"GET",
copyURL(u, "/v1/blueprints"),
encodeRequestWithToken(token, EncodeHTTPGenericRequest),
DecodeGetBlueprintsResponse,
opts...,
).Endpoint()
}
var getDEPAccountInfoEndpoint endpoint.Endpoint
{
@@ -105,7 +95,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
return Endpoints{
ListDevicesEndpoint: listDevicesEndpoint,
GetDEPTokensEndpoint: getDEPTokensEndpoint,
GetBlueprintsEndpoint: getBlueprintsEndpoint,
GetDEPAccountInfoEndpoint: getDEPAccountInfoEndpoint,
GetDEPDeviceEndpoint: getDEPDeviceDetailsEndpoint,
GetDEPProfileEndpoint: getDEPProfilesEndpoint,

View File

@@ -7,7 +7,6 @@ import (
"github.com/go-kit/kit/endpoint"
"github.com/micromdm/dep"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/deptoken"
"github.com/micromdm/micromdm/platform/user"
)
@@ -15,7 +14,6 @@ import (
type Endpoints struct {
ListDevicesEndpoint endpoint.Endpoint
GetDEPTokensEndpoint endpoint.Endpoint
GetBlueprintsEndpoint endpoint.Endpoint
GetDEPAccountInfoEndpoint endpoint.Endpoint
GetDEPDeviceEndpoint endpoint.Endpoint
GetDEPProfileEndpoint endpoint.Endpoint
@@ -58,15 +56,6 @@ func (e Endpoints) GetDEPTokens(ctx context.Context) ([]deptoken.DEPToken, []byt
return resp.(depTokenResponse).DEPTokens, resp.(depTokenResponse).DEPPubKey, nil
}
func (e Endpoints) GetBlueprints(ctx context.Context, opt GetBlueprintsOption) ([]blueprint.Blueprint, error) {
request := blueprintsRequest{opt}
response, err := e.GetBlueprintsEndpoint(ctx, request.Opts)
if err != nil {
return nil, err
}
return response.(blueprintsResponse).Blueprints, response.(blueprintsResponse).Err
}
func (e Endpoints) GetDEPAccountInfo(ctx context.Context) (*dep.Account, error) {
request := depAccountInforequest{}
response, err := e.GetDEPAccountInfoEndpoint(ctx, request)
@@ -138,17 +127,6 @@ func MakeGetDEPTokensEndpoint(svc Service) endpoint.Endpoint {
}
}
func MakeGetBlueprintsEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(blueprintsRequest)
blueprints, err := svc.GetBlueprints(ctx, req.Opts)
return blueprintsResponse{
Blueprints: blueprints,
Err: err,
}, nil
}
}
func MakeGetDEPAccountInfoEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
account, err := svc.GetDEPAccountInfo(ctx)
@@ -199,14 +177,6 @@ type depTokenResponse struct {
Err error `json:"err,omitempty"`
}
type blueprintsRequest struct{ Opts GetBlueprintsOption }
type blueprintsResponse struct {
Blueprints []blueprint.Blueprint `json:"blueprints"`
Err error `json:"err,omitempty"`
}
func (r blueprintsResponse) error() error { return r.Err }
type depAccountInforequest struct{}
type depAccountInfoResponse struct {
*dep.Account

View File

@@ -11,10 +11,8 @@ import (
"github.com/pkg/errors"
"github.com/micromdm/micromdm/platform/appstore"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/deptoken"
"github.com/micromdm/micromdm/platform/device"
"github.com/micromdm/micromdm/platform/profile"
"github.com/micromdm/micromdm/platform/pubsub"
"github.com/micromdm/micromdm/platform/user"
)
@@ -35,10 +33,6 @@ type ListUsersOption struct {
FilterUDID []string
}
type GetBlueprintsOption struct {
FilterName string
}
type ListAppsOption struct {
FilterName []string `json:"filter_name"`
}
@@ -47,7 +41,6 @@ type Service interface {
ListDevices(ctx context.Context, opt ListDevicesOption) ([]DeviceDTO, error)
ListUsers(ctx context.Context, opt ListUsersOption) ([]user.User, error)
GetDEPTokens(ctx context.Context) ([]deptoken.DEPToken, []byte, error)
GetBlueprints(ctx context.Context, opt GetBlueprintsOption) ([]blueprint.Blueprint, error)
ListApplications(ctx context.Context, opt ListAppsOption) ([]AppDTO, error)
DEPService
}
@@ -56,12 +49,10 @@ type ListService struct {
mtx sync.RWMutex
DEPClient dep.Client
Devices *device.DB
Blueprints *blueprint.DB
Profiles profile.Store
Tokens *deptoken.DB
Apps appstore.AppStore
Users *user.DB
Devices *device.DB
Tokens *deptoken.DB
Apps appstore.AppStore
Users *user.DB
}
func (svc *ListService) ListApplications(ctx context.Context, opts ListAppsOption) ([]AppDTO, error) {
@@ -155,19 +146,3 @@ func (svc *ListService) GetDEPTokens(ctx context.Context) ([]deptoken.DEPToken,
return tokens, certBytes, nil
}
func (svc *ListService) GetBlueprints(ctx context.Context, opt GetBlueprintsOption) ([]blueprint.Blueprint, error) {
if opt.FilterName != "" {
bp, err := svc.Blueprints.BlueprintByName(opt.FilterName)
if err != nil {
return nil, err
}
return []blueprint.Blueprint{*bp}, err
} else {
bps, err := svc.Blueprints.List()
if err != nil {
return nil, err
}
return bps, nil
}
}

View File

@@ -14,7 +14,6 @@ import (
type HTTPHandlers struct {
ListDevicesHandler http.Handler
GetDEPTokensHandler http.Handler
GetBlueprintsHandler http.Handler
GetDEPAccountInfoHandler http.Handler
GetDEPProfileHandler http.Handler
GetDEPDeviceDetailsHandler http.Handler
@@ -35,11 +34,6 @@ func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptran
decodeGetDEPTokensRequest,
encodeResponse,
opts...),
GetBlueprintsHandler: httptransport.NewServer(
endpoints.GetBlueprintsEndpoint,
decodeGetBlueprintsRequest,
encodeResponse,
opts...),
GetDEPAccountInfoHandler: httptransport.NewServer(
endpoints.GetDEPAccountInfoEndpoint,
decodeDepAccountInfoRequest,
@@ -90,17 +84,6 @@ func decodeListUsersRequest(ctx context.Context, r *http.Request) (interface{},
return req, nil
}
func decodeGetBlueprintsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var opts GetBlueprintsOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
return nil, err
}
req := blueprintsRequest{
Opts: opts,
}
return req, nil
}
func decodeDepAccountInfoRequest(ctx context.Context, r *http.Request) (interface{}, error) {
return nil, nil
}
@@ -192,15 +175,6 @@ func DecodeGetDEPTokensResponse(_ context.Context, r *http.Response) (interface{
return resp, err
}
func DecodeGetBlueprintsResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp blueprintsResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func DecodeDEPAccountInfoResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)

View File

@@ -16,17 +16,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
return nil, err
}
var removeBlueprintsEndpoint endpoint.Endpoint
{
removeBlueprintsEndpoint = httptransport.NewClient(
"DELETE",
copyURL(u, "/v1/blueprints"),
encodeRequestWithToken(token, EncodeHTTPGenericRequest),
DecodeBlueprintResponse,
opts...,
).Endpoint()
}
var unblockDeviceEndpoint endpoint.Endpoint
{
unblockDeviceEndpoint = httptransport.NewClient(
@@ -39,8 +28,7 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
}
return Endpoints{
RemoveBlueprintsEndpoint: removeBlueprintsEndpoint,
UnblockDeviceEndpoint: unblockDeviceEndpoint,
UnblockDeviceEndpoint: unblockDeviceEndpoint,
}, nil
}

View File

@@ -7,14 +7,12 @@ import (
)
type Endpoints struct {
RemoveBlueprintsEndpoint endpoint.Endpoint
UnblockDeviceEndpoint endpoint.Endpoint
UnblockDeviceEndpoint endpoint.Endpoint
}
func MakeEndpoints(svc Service) Endpoints {
e := Endpoints{
RemoveBlueprintsEndpoint: MakeRemoveBlueprintsEndpoint(svc),
UnblockDeviceEndpoint: MakeUnblockDeviceEndpoint(svc),
UnblockDeviceEndpoint: MakeUnblockDeviceEndpoint(svc),
}
return e
}
@@ -28,25 +26,6 @@ func (e Endpoints) UnblockDevice(ctx context.Context, udid string) error {
return resp.(unblockDeviceResponse).Err
}
func (e Endpoints) RemoveBlueprints(ctx context.Context, names []string) error {
request := blueprintRequest{Names: names}
resp, err := e.RemoveBlueprintsEndpoint(ctx, request)
if err != nil {
return err
}
return resp.(blueprintResponse).Err
}
func MakeRemoveBlueprintsEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(blueprintRequest)
err = svc.RemoveBlueprints(ctx, req.Names)
return blueprintResponse{
Err: err,
}, nil
}
}
func MakeUnblockDeviceEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(unblockDeviceRequest)

View File

@@ -3,28 +3,13 @@ package remove
import (
"context"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/remove"
)
type Service interface {
RemoveBlueprints(ctx context.Context, names []string) error
UnblockDevice(ctx context.Context, udid string) error
}
type RemoveService struct {
Blueprints *blueprint.DB
*remove.RemoveService
}
func (svc *RemoveService) RemoveBlueprints(ctx context.Context, names []string) error {
// TODO: Wrap deletion(s) in transactions so as to not have
// incomplete removals?
for _, name := range names {
err := svc.Blueprints.Delete(name)
if err != nil {
return err
}
}
return nil
}

View File

@@ -14,19 +14,11 @@ import (
)
type HTTPHandlers struct {
BlueprintHandler http.Handler
ProfileHandler http.Handler
UnblockDeviceHandler http.Handler
}
func MakeHTTPHandlers(ctx context.Context, endpoint Endpoints, opts ...httptransport.ServerOption) HTTPHandlers {
h := HTTPHandlers{
BlueprintHandler: httptransport.NewServer(
endpoint.RemoveBlueprintsEndpoint,
decodeBlueprintRequest,
encodeResponse,
opts...,
),
UnblockDeviceHandler: httptransport.NewServer(
endpoint.UnblockDeviceEndpoint,
decodeUnblockDeviceRequest,
@@ -37,22 +29,6 @@ func MakeHTTPHandlers(ctx context.Context, endpoint Endpoints, opts ...httptrans
return h
}
func decodeBlueprintRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var bpReq blueprintRequest
if err := json.NewDecoder(r.Body).Decode(&bpReq); err != nil {
return nil, err
}
return bpReq, nil
}
func decodeProfileRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req profileRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
return req, nil
}
func decodeUnblockDeviceRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var errBadRoute = errors.New("bad route")
var req unblockDeviceRequest
@@ -117,24 +93,6 @@ func encodeUnblockDeviceRequest(_ context.Context, r *http.Request, request inte
return nil
}
func DecodeBlueprintResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp blueprintResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func DecodeProfileResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp profileResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func DecodeUnblockDeviceResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)

View File

@@ -0,0 +1,59 @@
package blueprint
import (
"context"
"encoding/json"
"net/http"
"github.com/go-kit/kit/endpoint"
)
func (svc *BlueprintService) ApplyBlueprint(ctx context.Context, bp *Blueprint) error {
return svc.store.Save(bp)
}
type applyBlueprintRequest struct {
Blueprint *Blueprint `json:"blueprint"`
}
type applyBlueprintResponse struct {
Err error `json:"err,omitempty"`
}
func (r applyBlueprintResponse) error() error { return r.Err }
func decodeApplyBlueprintRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var bpReq applyBlueprintRequest
if err := json.NewDecoder(r.Body).Decode(&bpReq); err != nil {
return nil, err
}
return bpReq, nil
}
func decodeApplyBlueprintResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp applyBlueprintResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func MakeApplyBlueprintEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(applyBlueprintRequest)
err = svc.ApplyBlueprint(ctx, req.Blueprint)
return applyBlueprintResponse{
Err: err,
}, nil
}
}
func (e Endpoints) ApplyBlueprint(ctx context.Context, bp *Blueprint) error {
request := applyBlueprintRequest{Blueprint: bp}
resp, err := e.ApplyBlueprintEndpoint(ctx, request)
if err != nil {
return err
}
return resp.(applyBlueprintResponse).Err
}

View File

@@ -1,4 +1,4 @@
package blueprint
package builtin
import (
"fmt"
@@ -7,6 +7,7 @@ import (
"github.com/boltdb/bolt"
"github.com/pkg/errors"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/profile"
"github.com/micromdm/micromdm/platform/user"
)
@@ -46,7 +47,7 @@ func NewDB(
return datastore, nil
}
func (db *DB) Create(bp *Blueprint) error {
func (db *DB) Create(bp *blueprint.Blueprint) error {
_, err := db.BlueprintByName(bp.Name)
if err != nil && isNotFound(err) {
return errors.New("blueprint must have a unique name")
@@ -57,15 +58,15 @@ func (db *DB) Create(bp *Blueprint) error {
return db.Save(bp)
}
func (db *DB) List() ([]Blueprint, error) {
func (db *DB) List() ([]blueprint.Blueprint, error) {
// TODO add filter/limit with ForEach
var blueprints []Blueprint
var blueprints []blueprint.Blueprint
err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(BlueprintBucket))
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
var bp Blueprint
if err := UnmarshalBlueprint(v, &bp); err != nil {
var bp blueprint.Blueprint
if err := blueprint.UnmarshalBlueprint(v, &bp); err != nil {
return err
}
blueprints = append(blueprints, bp)
@@ -75,7 +76,7 @@ func (db *DB) List() ([]Blueprint, error) {
return blueprints, err
}
func (db *DB) Save(bp *Blueprint) error {
func (db *DB) Save(bp *blueprint.Blueprint) error {
err := bp.Verify()
if err != nil {
return err
@@ -97,7 +98,7 @@ func (db *DB) Save(bp *Blueprint) error {
if bkt == nil {
return fmt.Errorf("bucket %q not found!", BlueprintBucket)
}
bpproto, err := MarshalBlueprint(bp)
bpproto, err := blueprint.MarshalBlueprint(bp)
if err != nil {
return errors.Wrap(err, "marshalling blueprint")
}
@@ -123,8 +124,8 @@ func (db *DB) Save(bp *Blueprint) error {
return tx.Commit()
}
func (db *DB) BlueprintByName(name string) (*Blueprint, error) {
var bp Blueprint
func (db *DB) BlueprintByName(name string) (*blueprint.Blueprint, error) {
var bp blueprint.Blueprint
err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(BlueprintBucket))
ib := tx.Bucket([]byte(blueprintIndexBucket))
@@ -136,7 +137,7 @@ func (db *DB) BlueprintByName(name string) (*Blueprint, error) {
if idx == nil {
return &notFound{"Blueprint", fmt.Sprintf("uuid %s", string(idx))}
}
return UnmarshalBlueprint(v, &bp)
return blueprint.UnmarshalBlueprint(v, &bp)
})
if err != nil {
return nil, err
@@ -144,8 +145,8 @@ func (db *DB) BlueprintByName(name string) (*Blueprint, error) {
return &bp, nil
}
func (db *DB) BlueprintsByApplyAt(name string) ([]*Blueprint, error) {
var bps []*Blueprint
func (db *DB) BlueprintsByApplyAt(name string) ([]*blueprint.Blueprint, error) {
var bps []*blueprint.Blueprint
err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(BlueprintBucket))
c := b.Cursor()
@@ -153,8 +154,8 @@ func (db *DB) BlueprintsByApplyAt(name string) ([]*Blueprint, error) {
// an array of Blueprints or other more efficient means. Looping
// over every blueprint is quite inefficient!
for k, v := c.First(); k != nil; k, v = c.Next() {
var bp Blueprint
err := UnmarshalBlueprint(v, &bp)
var bp blueprint.Blueprint
err := blueprint.UnmarshalBlueprint(v, &bp)
if err != nil {
fmt.Println("could not Unmarshal Blueprint")
continue

View File

@@ -1,4 +1,4 @@
package blueprint
package builtin
import (
"context"
@@ -8,13 +8,14 @@ import (
"github.com/pkg/errors"
"github.com/micromdm/micromdm/mdm/checkin"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/command"
"github.com/micromdm/micromdm/platform/device"
"github.com/micromdm/micromdm/platform/profile"
"github.com/micromdm/micromdm/platform/pubsub"
)
func (db *DB) ApplyToDevice(ctx context.Context, svc command.Service, bp *Blueprint, udid string) error {
func (db *DB) ApplyToDevice(ctx context.Context, svc command.Service, bp *blueprint.Blueprint, udid string) error {
var requests []*mdm.CommandRequest
for _, uuid := range bp.UserUUID {
fmt.Println("Adding user to admin account")
@@ -107,7 +108,7 @@ func (db *DB) StartListener(sub pubsub.Subscriber, cmdSvc command.Service) error
// skip UserID token updates
continue
}
bps, err := db.BlueprintsByApplyAt(ApplyAtEnroll)
bps, err := db.BlueprintsByApplyAt(blueprint.ApplyAtEnroll)
if err != nil {
fmt.Println(err)
continue

View File

@@ -0,0 +1,70 @@
package blueprint
import (
"context"
"net/http"
"net/url"
"github.com/go-kit/kit/endpoint"
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
)
func NewHTTPClient(instance, token string, logger log.Logger, opts ...httptransport.ClientOption) (Service, error) {
u, err := url.Parse(instance)
if err != nil {
return nil, err
}
var applyBlueprintEndpoint endpoint.Endpoint
{
applyBlueprintEndpoint = httptransport.NewClient(
"PUT",
copyURL(u, "/v1/blueprints"),
encodeRequestWithToken(token, httptransport.EncodeJSONRequest),
decodeApplyBlueprintResponse,
opts...,
).Endpoint()
}
var getBlueprintsEndpoint endpoint.Endpoint
{
getBlueprintsEndpoint = httptransport.NewClient(
"GET",
copyURL(u, "/v1/blueprints"),
encodeRequestWithToken(token, httptransport.EncodeJSONRequest),
decodeGetBlueprintsResponse,
opts...,
).Endpoint()
}
var removeBlueprintsEndpoint endpoint.Endpoint
{
removeBlueprintsEndpoint = httptransport.NewClient(
"DELETE",
copyURL(u, "/v1/blueprints"),
encodeRequestWithToken(token, httptransport.EncodeJSONRequest),
decodeRemoveBlueprintsResponse,
opts...,
).Endpoint()
}
return Endpoints{
ApplyBlueprintEndpoint: applyBlueprintEndpoint,
GetBlueprintsEndpoint: getBlueprintsEndpoint,
RemoveBlueprintsEndpoint: removeBlueprintsEndpoint,
}, nil
}
func encodeRequestWithToken(token string, next httptransport.EncodeRequestFunc) httptransport.EncodeRequestFunc {
return func(ctx context.Context, r *http.Request, request interface{}) error {
r.SetBasicAuth("micromdm", token)
return next(ctx, r, request)
}
}
func copyURL(base *url.URL, path string) *url.URL {
next := *base
next.Path = path
return &next
}

View File

@@ -0,0 +1,73 @@
package blueprint
import (
"context"
"encoding/json"
"net/http"
"github.com/go-kit/kit/endpoint"
)
func (svc *BlueprintService) GetBlueprints(ctx context.Context, opt GetBlueprintsOption) ([]Blueprint, error) {
if opt.FilterName != "" {
bp, err := svc.store.BlueprintByName(opt.FilterName)
if err != nil {
return nil, err
}
return []Blueprint{*bp}, err
} else {
bps, err := svc.store.List()
if err != nil {
return nil, err
}
return bps, nil
}
}
type getBlueprintsRequest struct{ Opts GetBlueprintsOption }
type getBlueprintsResponse struct {
Blueprints []Blueprint `json:"blueprints"`
Err error `json:"err,omitempty"`
}
func (r getBlueprintsResponse) error() error { return r.Err }
func decodeGetBlueprintsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var opts GetBlueprintsOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
return nil, err
}
req := getBlueprintsRequest{
Opts: opts,
}
return req, nil
}
func decodeGetBlueprintsResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp getBlueprintsResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func MakeGetBlueprintsEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(getBlueprintsRequest)
blueprints, err := svc.GetBlueprints(ctx, req.Opts)
return getBlueprintsResponse{
Blueprints: blueprints,
Err: err,
}, nil
}
}
func (e Endpoints) GetBlueprints(ctx context.Context, opt GetBlueprintsOption) ([]Blueprint, error) {
request := getBlueprintsRequest{opt}
response, err := e.GetBlueprintsEndpoint(ctx, request.Opts)
if err != nil {
return nil, err
}
return response.(getBlueprintsResponse).Blueprints, response.(getBlueprintsResponse).Err
}

View File

@@ -0,0 +1,65 @@
package blueprint
import (
"context"
"encoding/json"
"net/http"
"github.com/go-kit/kit/endpoint"
)
func (svc *BlueprintService) RemoveBlueprints(ctx context.Context, names []string) error {
for _, name := range names {
err := svc.store.Delete(name)
if err != nil {
return err
}
}
return nil
}
type removeBlueprintsRequest struct {
Names []string `json:"names"`
}
type removeBlueprintsResponse struct {
Err error `json:"err,omitempty"`
}
func (r removeBlueprintsResponse) error() error { return r.Err }
func decodeRemoveBlueprintsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req removeBlueprintsRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
return req, nil
}
func decodeRemoveBlueprintsResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp removeBlueprintsResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func MakeRemoveBlueprintsEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(removeBlueprintsRequest)
err = svc.RemoveBlueprints(ctx, req.Names)
return removeBlueprintsResponse{
Err: err,
}, nil
}
}
func (e Endpoints) RemoveBlueprints(ctx context.Context, names []string) error {
request := removeBlueprintsRequest{Names: names}
resp, err := e.RemoveBlueprintsEndpoint(ctx, request)
if err != nil {
return err
}
return resp.(removeBlueprintsResponse).Err
}

View File

@@ -0,0 +1,76 @@
package blueprint
import (
"encoding/json"
"net/http"
"github.com/go-kit/kit/endpoint"
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
"github.com/gorilla/mux"
"github.com/pkg/errors"
)
type Endpoints struct {
ApplyBlueprintEndpoint endpoint.Endpoint
GetBlueprintsEndpoint endpoint.Endpoint
RemoveBlueprintsEndpoint endpoint.Endpoint
}
func MakeServerEndpoints(s Service) Endpoints {
return Endpoints{
GetBlueprintsEndpoint: MakeGetBlueprintsEndpoint(s),
ApplyBlueprintEndpoint: MakeApplyBlueprintEndpoint(s),
}
}
func MakeHTTPHandler(e Endpoints, logger log.Logger) http.Handler {
options := []httptransport.ServerOption{
httptransport.ServerErrorLogger(logger),
}
r := mux.NewRouter()
// PUT /v1/blueprints create or replace a blueprint on the server
// GET /v1/blueprints get a list of blueprints managed by the server
// DELETE /v1/blueprints remove one or more blueprints from the server
r.Methods("PUT").Path("/v1/blueprints").Handler(httptransport.NewServer(
e.ApplyBlueprintEndpoint,
decodeApplyBlueprintRequest,
httptransport.EncodeJSONResponse,
options...,
))
r.Methods("GET").Path("/v1/blueprints").Handler(httptransport.NewServer(
e.GetBlueprintsEndpoint,
decodeGetBlueprintsRequest,
httptransport.EncodeJSONResponse,
options...,
))
r.Methods("DELETE").Path("/v1/blueprints").Handler(httptransport.NewServer(
e.RemoveBlueprintsEndpoint,
decodeRemoveBlueprintsRequest,
httptransport.EncodeJSONResponse,
options...,
))
return r
}
type errorWrapper struct {
Error string `json:"error"`
}
type errorer interface {
error() error
}
func errorDecoder(r *http.Response) error {
var w errorWrapper
if err := json.NewDecoder(r.Body).Decode(&w); err != nil {
return err
}
return errors.New(w.Error)
}

View File

@@ -0,0 +1,30 @@
package blueprint
import (
"context"
)
type GetBlueprintsOption struct {
FilterName string
}
type Service interface {
ApplyBlueprint(ctx context.Context, bp *Blueprint) error
GetBlueprints(ctx context.Context, opt GetBlueprintsOption) ([]Blueprint, error)
RemoveBlueprints(ctx context.Context, names []string) error
}
type Store interface {
Save(*Blueprint) error
BlueprintByName(name string) (*Blueprint, error)
List() ([]Blueprint, error)
Delete(string) error
}
type BlueprintService struct {
store Store
}
func New(store Store) *BlueprintService {
return &BlueprintService{store: store}
}