reorganize profile service (#347)

Moved all the endpoints into the profile package.
Defined a Store interface which includes all the used BoltDB methods.
Moved the BoltDB implementation into a subpackage.
This commit is contained in:
Victor Vrantchan
2017-12-09 16:50:10 -05:00
committed by GitHub
parent ce6e18f18d
commit 83ea8491aa
27 changed files with 487 additions and 265 deletions

View File

@@ -13,18 +13,16 @@ import (
"strings"
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
"github.com/pkg/errors"
uuid "github.com/satori/go.uuid"
"github.com/micromdm/micromdm/platform/api/server/apply"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/profile"
)
type applyCommand struct {
config *ServerConfig
applysvc apply.Service
config *ServerConfig
*remoteServices
}
func (cmd *applyCommand) setup() error {
@@ -34,11 +32,11 @@ func (cmd *applyCommand) setup() error {
}
cmd.config = cfg
logger := log.NewLogfmtLogger(os.Stderr)
applysvc, err := apply.NewClient(cfg.ServerURL, logger, cfg.APIToken, httptransport.SetClient(skipVerifyHTTPClient(cmd.config.SkipVerify)))
remote, err := setupClient(logger)
if err != nil {
return err
}
cmd.applysvc = applysvc
cmd.remoteServices = remote
return nil
}
@@ -256,7 +254,7 @@ func (cmd *applyCommand) applyProfile(args []string) error {
}
ctx := context.Background()
err = cmd.applysvc.ApplyProfile(ctx, &p)
err = cmd.profilesvc.ApplyProfile(ctx, &p)
if err != nil {
return err
}

View File

@@ -13,16 +13,16 @@ import (
"crypto/x509"
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
"github.com/pkg/errors"
"github.com/micromdm/micromdm/pkg/crypto"
"github.com/micromdm/micromdm/platform/api/server/list"
"github.com/micromdm/micromdm/platform/profile"
)
type getCommand struct {
config *ServerConfig
list list.Service
*remoteServices
}
func (cmd *getCommand) setup() error {
@@ -32,11 +32,12 @@ func (cmd *getCommand) setup() error {
}
cmd.config = cfg
logger := log.NewLogfmtLogger(os.Stderr)
listsvc, err := list.NewClient(cfg.ServerURL, logger, cfg.APIToken, httptransport.SetClient(skipVerifyHTTPClient(cmd.config.SkipVerify)))
remote, err := setupClient(logger)
if err != nil {
return err
}
cmd.list = listsvc
cmd.remoteServices = remote
return nil
}
@@ -304,7 +305,7 @@ func (cmd *getCommand) getProfiles(args []string) error {
}
ctx := context.Background()
profiles, err := cmd.list.GetProfiles(ctx, list.GetProfilesOption{Identifier: *flIdentifier})
profiles, err := cmd.profilesvc.GetProfiles(ctx, profile.GetProfilesOption{Identifier: *flIdentifier})
if err != nil {
return err
}

View File

@@ -6,15 +6,11 @@ import (
"strings"
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
"github.com/micromdm/micromdm/platform/api/server/remove"
)
type removeCommand struct {
config *ServerConfig
remove remove.Service
*remoteServices
}
func (cmd *removeCommand) setup() error {
@@ -24,11 +20,11 @@ func (cmd *removeCommand) setup() error {
}
cmd.config = cfg
logger := log.NewLogfmtLogger(os.Stderr)
rmsvc, err := remove.NewClient(cfg.ServerURL, logger, cfg.APIToken, httptransport.SetClient(skipVerifyHTTPClient(cmd.config.SkipVerify)))
remote, err := setupClient(logger)
if err != nil {
return err
}
cmd.remove = rmsvc
cmd.remoteServices = remote
return nil
}

View File

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

59
cmd/mdmctl/setup.go Normal file
View File

@@ -0,0 +1,59 @@
package main
import (
"github.com/go-kit/kit/log"
httptransport "github.com/go-kit/kit/transport/http"
"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/profile"
)
type remoteServices struct {
profilesvc profile.Service
applysvc apply.Service
list list.Service
remove remove.Service
}
func setupClient(logger log.Logger) (*remoteServices, error) {
cfg, err := LoadServerConfig()
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
}
profilesvc, err := profile.NewHTTPClient(
cfg.ServerURL, cfg.APIToken, logger,
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)))
if err != nil {
return nil, err
}
rmsvc, err := remove.NewClient(
cfg.ServerURL, logger, cfg.APIToken,
httptransport.SetClient(skipVerifyHTTPClient(cfg.SkipVerify)))
if err != nil {
return nil, err
}
return &remoteServices{
profilesvc: profilesvc,
applysvc: applysvc,
list: listsvc,
remove: rmsvc,
}, nil
}

View File

@@ -54,6 +54,7 @@ import (
"github.com/micromdm/micromdm/platform/deptoken"
"github.com/micromdm/micromdm/platform/device"
"github.com/micromdm/micromdm/platform/profile"
profilebuiltin "github.com/micromdm/micromdm/platform/profile/builtin"
"github.com/micromdm/micromdm/platform/pubsub"
"github.com/micromdm/micromdm/platform/pubsub/inmem"
"github.com/micromdm/micromdm/platform/queue"
@@ -175,7 +176,7 @@ func serve(args []string) error {
stdlog.Fatal(err)
}
sm.profileDB, err = profile.NewDB(sm.db)
sm.profileDB, err = profilebuiltin.NewDB(sm.db)
if err != nil {
stdlog.Fatal(err)
}
@@ -269,6 +270,13 @@ func serve(args []string) error {
tokenDB := &deptoken.DB{DB: sm.db, Publisher: sm.pubclient}
appDB := &appstore.Repo{Path: *flRepoPath}
var profilesvc profile.Service
{
profilesvc = profile.New(sm.profileDB)
}
profileEndpoints := profile.MakeServerEndpoints(profilesvc)
var listsvc list.Service
{
l := &list.ListService{
@@ -276,7 +284,6 @@ func serve(args []string) error {
Devices: devDB,
Tokens: tokenDB,
Blueprints: bpDB,
Profiles: sm.profileDB,
Apps: appDB,
Users: userDB,
}
@@ -295,7 +302,6 @@ func serve(args []string) error {
ListDevicesEndpoint: listDevicesEndpoint,
GetDEPTokensEndpoint: list.MakeGetDEPTokensEndpoint(listsvc),
GetBlueprintsEndpoint: list.MakeGetBlueprintsEndpoint(listsvc),
GetProfilesEndpoint: list.MakeGetProfilesEndpoint(listsvc),
GetDEPAccountInfoEndpoint: list.MakeGetDEPAccountInfoEndpoint(listsvc),
GetDEPProfileEndpoint: list.MakeGetDEPProfileEndpoint(listsvc),
GetDEPDeviceEndpoint: list.MakeGetDEPDeviceDetailsEndpoint(listsvc),
@@ -309,7 +315,6 @@ func serve(args []string) error {
DEPClient: dc,
Blueprints: bpDB,
Tokens: tokenDB,
Profiles: sm.profileDB,
Apps: appDB,
Users: userDB,
RemoveService: removeService,
@@ -325,11 +330,6 @@ func serve(args []string) error {
applyBlueprintEndpoint = apply.MakeApplyBlueprintEndpoint(applysvc)
}
var applyProfileEndpoint endpoint.Endpoint
{
applyProfileEndpoint = apply.MakeApplyProfileEndpoint(applysvc)
}
var defineDEPProfileEndpoint endpoint.Endpoint
{
defineDEPProfileEndpoint = apply.MakeDefineDEPProfile(applysvc)
@@ -348,7 +348,6 @@ func serve(args []string) error {
applyEndpoints := apply.Endpoints{
ApplyBlueprintEndpoint: applyBlueprintEndpoint,
ApplyDEPTokensEndpoint: apply.MakeApplyDEPTokensEndpoint(applysvc),
ApplyProfileEndpoint: applyProfileEndpoint,
DefineDEPProfileEndpoint: defineDEPProfileEndpoint,
AppUploadEndpoint: appUploadEndpoint,
ApplyUserEndpoint: applyUserEndpoint,
@@ -359,7 +358,7 @@ func serve(args []string) error {
listAPIHandlers := list.MakeHTTPHandlers(ctx, listEndpoints, connectOpts...)
rmsvc := &remove.RemoveService{Blueprints: bpDB, Profiles: sm.profileDB, RemoveService: removeService}
rmsvc := &remove.RemoveService{Blueprints: bpDB, RemoveService: removeService}
removeAPIHandlers := remove.MakeHTTPHandlers(ctx, remove.MakeEndpoints(rmsvc), connectOpts...)
connectHandlers := connect.MakeHTTPHandlers(ctx, connectEndpoints, connectOpts...)
@@ -378,8 +377,11 @@ func serve(args []string) error {
io.WriteString(w, homePage)
})
profilesHandler := profile.MakeHTTPHandler(profileEndpoints, logger)
// API commands. Only handled if the user provides an api key.
if *flAPIKey != "" {
r.Handle("/v1/profiles", apiAuthMiddleware(*flAPIKey, profilesHandler))
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")
@@ -390,9 +392,6 @@ func serve(args []string) error {
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/profiles", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetProfilesHandler)).Methods("GET")
r.Handle("/v1/profiles", apiAuthMiddleware(*flAPIKey, applyAPIHandlers.ProfileHandler)).Methods("PUT")
r.Handle("/v1/profiles", apiAuthMiddleware(*flAPIKey, removeAPIHandlers.ProfileHandler)).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")
@@ -496,7 +495,7 @@ type server struct {
APNSPrivateKeyPass string
tlsCertPath string
scepDepot *boltdepot.Depot
profileDB *profile.DB
profileDB profile.Store
configDB *config.DB
removeDB *block.DB
CommandWebhookURL string

View File

@@ -29,7 +29,7 @@ type Service interface {
OTAPhase3(ctx context.Context) (profile.Mobileconfig, error)
}
func NewService(topic TopicProvider, sub pubsub.Subscriber, caCertPath, scepURL, scepChallenge, url, tlsCertPath, scepSubject string, profileDB *profile.DB) (Service, error) {
func NewService(topic TopicProvider, sub pubsub.Subscriber, caCertPath, scepURL, scepChallenge, url, tlsCertPath, scepSubject string, profileDB profile.Store) (Service, error) {
var caCert, tlsCert []byte
var err error
@@ -120,7 +120,7 @@ type service struct {
SCEPSubject [][][]string
CACert []byte
TLSCert []byte
ProfileDB *profile.DB
ProfileDB profile.Store
topicProvier TopicProvider

View File

@@ -36,16 +36,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
opts...,
).Endpoint()
}
var applyProfileEndpoint endpoint.Endpoint
{
applyProfileEndpoint = httptransport.NewClient(
"PUT",
copyURL(u, "/v1/profiles"),
encodeRequestWithToken(token, EncodeHTTPGenericRequest),
DecodeProfileResponse,
opts...,
).Endpoint()
}
var defineDEPProfileEndpoint endpoint.Endpoint
{
@@ -94,7 +84,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
return Endpoints{
ApplyBlueprintEndpoint: applyBlueprintEndpoint,
ApplyDEPTokensEndpoint: applyDEPTokensEndpoint,
ApplyProfileEndpoint: applyProfileEndpoint,
DefineDEPProfileEndpoint: defineDEPProfileEndpoint,
AppUploadEndpoint: uploadAppEndpoint,
ApplyUserEndpoint: applyUserEndpoint,

View File

@@ -8,14 +8,12 @@ import (
"github.com/micromdm/dep"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/profile"
"github.com/micromdm/micromdm/platform/user"
)
type Endpoints struct {
ApplyBlueprintEndpoint endpoint.Endpoint
ApplyDEPTokensEndpoint endpoint.Endpoint
ApplyProfileEndpoint endpoint.Endpoint
DefineDEPProfileEndpoint endpoint.Endpoint
AppUploadEndpoint endpoint.Endpoint
ApplyUserEndpoint endpoint.Endpoint
@@ -87,15 +85,6 @@ func (e Endpoints) ApplyDEPToken(ctx context.Context, P7MContent []byte) error {
return resp.(depTokensResponse).Err
}
func (e Endpoints) ApplyProfile(ctx context.Context, p *profile.Profile) error {
request := profileRequest{Profile: p}
resp, err := e.ApplyProfileEndpoint(ctx, request)
if err != nil {
return err
}
return resp.(profileResponse).Err
}
func MakeApplyBlueprintEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(blueprintRequest)
@@ -116,16 +105,6 @@ func MakeApplyDEPTokensEndpoint(svc Service) endpoint.Endpoint {
}
}
func MakeApplyProfileEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(profileRequest)
err = svc.ApplyProfile(ctx, req.Profile)
return profileResponse{
Err: err,
}, nil
}
}
func MakeDefineDEPProfile(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(depProfileRequest)
@@ -192,16 +171,6 @@ type blueprintResponse struct {
func (r blueprintResponse) error() error { return r.Err }
type profileRequest struct {
Profile *profile.Profile `json:"profile"`
}
type profileResponse struct {
Err error `json:"err,omitempty"`
}
func (r profileResponse) error() error { return r.Err }
type depTokensRequest struct {
P7MContent []byte `json:"p7m_content"`
}

View File

@@ -19,7 +19,6 @@ import (
"github.com/micromdm/micromdm/platform/appstore"
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/deptoken"
"github.com/micromdm/micromdm/platform/profile"
"github.com/micromdm/micromdm/platform/pubsub"
"github.com/micromdm/micromdm/platform/remove"
"github.com/micromdm/micromdm/platform/user"
@@ -28,7 +27,6 @@ import (
type Service interface {
ApplyBlueprint(ctx context.Context, bp *blueprint.Blueprint) error
ApplyDEPToken(ctx context.Context, P7MContent []byte) error
ApplyProfile(ctx context.Context, p *profile.Profile) 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)
DEPService
@@ -40,7 +38,6 @@ type ApplyService struct {
DEPClient dep.Client
Blueprints *blueprint.DB
Profiles *profile.DB
Tokens *deptoken.DB
Apps appstore.AppStore
Users *user.DB
@@ -180,7 +177,3 @@ func (svc *ApplyService) ApplyDEPToken(ctx context.Context, P7MContent []byte) e
log.Println("stored DEP token with ck", depToken.ConsumerKey)
return nil
}
func (svc *ApplyService) ApplyProfile(ctx context.Context, p *profile.Profile) error {
return svc.Profiles.Save(p)
}

View File

@@ -18,7 +18,6 @@ import (
type HTTPHandlers struct {
BlueprintHandler http.Handler
DEPTokensHandler http.Handler
ProfileHandler http.Handler
DefineDEPProfileHandler http.Handler
AppUploadHandler http.Handler
ApplyUserhandler http.Handler
@@ -39,12 +38,6 @@ func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptran
encodeResponse,
opts...,
),
ProfileHandler: httptransport.NewServer(
endpoints.ApplyProfileEndpoint,
decodeProfileRequest,
encodeResponse,
opts...,
),
DefineDEPProfileHandler: httptransport.NewServer(
endpoints.DefineDEPProfileEndpoint,
decodeDEPProfileRequest,
@@ -101,14 +94,6 @@ func decodeBlueprintRequest(ctx context.Context, r *http.Request) (interface{},
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 decodeDEPProfileRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req depProfileRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -254,15 +239,6 @@ func DecodeDEPTokensResponse(_ context.Context, r *http.Response) (interface{},
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 DecodeDEPProfileResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)

View File

@@ -46,16 +46,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
opts...,
).Endpoint()
}
var getProfilesEndpoint endpoint.Endpoint
{
getProfilesEndpoint = httptransport.NewClient(
"GET",
copyURL(u, "/v1/profiles"),
encodeRequestWithToken(token, EncodeHTTPGenericRequest),
DecodeGetProfilesResponse,
opts...,
).Endpoint()
}
var getDEPAccountInfoEndpoint endpoint.Endpoint
{
@@ -116,7 +106,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
ListDevicesEndpoint: listDevicesEndpoint,
GetDEPTokensEndpoint: getDEPTokensEndpoint,
GetBlueprintsEndpoint: getBlueprintsEndpoint,
GetProfilesEndpoint: getProfilesEndpoint,
GetDEPAccountInfoEndpoint: getDEPAccountInfoEndpoint,
GetDEPDeviceEndpoint: getDEPDeviceDetailsEndpoint,
GetDEPProfileEndpoint: getDEPProfilesEndpoint,

View File

@@ -9,7 +9,6 @@ import (
"github.com/micromdm/micromdm/platform/blueprint"
"github.com/micromdm/micromdm/platform/deptoken"
"github.com/micromdm/micromdm/platform/profile"
"github.com/micromdm/micromdm/platform/user"
)
@@ -17,7 +16,6 @@ type Endpoints struct {
ListDevicesEndpoint endpoint.Endpoint
GetDEPTokensEndpoint endpoint.Endpoint
GetBlueprintsEndpoint endpoint.Endpoint
GetProfilesEndpoint endpoint.Endpoint
GetDEPAccountInfoEndpoint endpoint.Endpoint
GetDEPDeviceEndpoint endpoint.Endpoint
GetDEPProfileEndpoint endpoint.Endpoint
@@ -69,15 +67,6 @@ func (e Endpoints) GetBlueprints(ctx context.Context, opt GetBlueprintsOption) (
return response.(blueprintsResponse).Blueprints, response.(blueprintsResponse).Err
}
func (e Endpoints) GetProfiles(ctx context.Context, opt GetProfilesOption) ([]profile.Profile, error) {
request := profilesRequest{opt}
response, err := e.GetProfilesEndpoint(ctx, request.Opts)
if err != nil {
return nil, err
}
return response.(profilesResponse).Profiles, response.(profilesResponse).Err
}
func (e Endpoints) GetDEPAccountInfo(ctx context.Context) (*dep.Account, error) {
request := depAccountInforequest{}
response, err := e.GetDEPAccountInfoEndpoint(ctx, request)
@@ -160,17 +149,6 @@ func MakeGetBlueprintsEndpoint(svc Service) endpoint.Endpoint {
}
}
func MakeGetProfilesEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(profilesRequest)
profiles, err := svc.GetProfiles(ctx, req.Opts)
return profilesResponse{
Profiles: profiles,
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)
@@ -229,14 +207,6 @@ type blueprintsResponse struct {
func (r blueprintsResponse) error() error { return r.Err }
type profilesRequest struct{ Opts GetProfilesOption }
type profilesResponse struct {
Profiles []profile.Profile `json:"profiles"`
Err error `json:"err,omitempty"`
}
func (r profilesResponse) error() error { return r.Err }
type depAccountInforequest struct{}
type depAccountInfoResponse struct {
*dep.Account

View File

@@ -39,10 +39,6 @@ type GetBlueprintsOption struct {
FilterName string
}
type GetProfilesOption struct {
Identifier string `json:"id"`
}
type ListAppsOption struct {
FilterName []string `json:"filter_name"`
}
@@ -52,7 +48,6 @@ type Service interface {
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)
GetProfiles(ctx context.Context, opt GetProfilesOption) ([]profile.Profile, error)
ListApplications(ctx context.Context, opt ListAppsOption) ([]AppDTO, error)
DEPService
}
@@ -63,7 +58,7 @@ type ListService struct {
Devices *device.DB
Blueprints *blueprint.DB
Profiles *profile.DB
Profiles profile.Store
Tokens *deptoken.DB
Apps appstore.AppStore
Users *user.DB
@@ -176,15 +171,3 @@ func (svc *ListService) GetBlueprints(ctx context.Context, opt GetBlueprintsOpti
return bps, nil
}
}
func (svc *ListService) GetProfiles(ctx context.Context, opt GetProfilesOption) ([]profile.Profile, error) {
if opt.Identifier != "" {
foundProf, err := svc.Profiles.ProfileById(opt.Identifier)
if err != nil {
return nil, err
}
return []profile.Profile{*foundProf}, nil
} else {
return svc.Profiles.List()
}
}

View File

@@ -15,7 +15,6 @@ type HTTPHandlers struct {
ListDevicesHandler http.Handler
GetDEPTokensHandler http.Handler
GetBlueprintsHandler http.Handler
GetProfilesHandler http.Handler
GetDEPAccountInfoHandler http.Handler
GetDEPProfileHandler http.Handler
GetDEPDeviceDetailsHandler http.Handler
@@ -41,11 +40,6 @@ func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptran
decodeGetBlueprintsRequest,
encodeResponse,
opts...),
GetProfilesHandler: httptransport.NewServer(
endpoints.GetProfilesEndpoint,
decodeGetProfilesRequest,
encodeResponse,
opts...),
GetDEPAccountInfoHandler: httptransport.NewServer(
endpoints.GetDEPAccountInfoEndpoint,
decodeDepAccountInfoRequest,
@@ -107,17 +101,6 @@ func decodeGetBlueprintsRequest(ctx context.Context, r *http.Request) (interface
return req, nil
}
func decodeGetProfilesRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var opts GetProfilesOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
return nil, err
}
req := profilesRequest{
Opts: opts,
}
return req, nil
}
func decodeDepAccountInfoRequest(ctx context.Context, r *http.Request) (interface{}, error) {
return nil, nil
}
@@ -218,15 +201,6 @@ func DecodeGetBlueprintsResponse(_ context.Context, r *http.Response) (interface
return resp, err
}
func DecodeGetProfilesResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp profilesResponse
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

@@ -26,16 +26,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
opts...,
).Endpoint()
}
var removeProfilesEndpoint endpoint.Endpoint
{
removeProfilesEndpoint = httptransport.NewClient(
"DELETE",
copyURL(u, "/v1/profiles"),
encodeRequestWithToken(token, EncodeHTTPGenericRequest),
DecodeProfileResponse,
opts...,
).Endpoint()
}
var unblockDeviceEndpoint endpoint.Endpoint
{
@@ -50,7 +40,6 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
return Endpoints{
RemoveBlueprintsEndpoint: removeBlueprintsEndpoint,
RemoveProfilesEndpoint: removeProfilesEndpoint,
UnblockDeviceEndpoint: unblockDeviceEndpoint,
}, nil
}

View File

@@ -8,14 +8,12 @@ import (
type Endpoints struct {
RemoveBlueprintsEndpoint endpoint.Endpoint
RemoveProfilesEndpoint endpoint.Endpoint
UnblockDeviceEndpoint endpoint.Endpoint
}
func MakeEndpoints(svc Service) Endpoints {
e := Endpoints{
RemoveBlueprintsEndpoint: MakeRemoveBlueprintsEndpoint(svc),
RemoveProfilesEndpoint: MakeRemoveProfilesEndpoint(svc),
UnblockDeviceEndpoint: MakeUnblockDeviceEndpoint(svc),
}
return e
@@ -39,15 +37,6 @@ func (e Endpoints) RemoveBlueprints(ctx context.Context, names []string) error {
return resp.(blueprintResponse).Err
}
func (e Endpoints) RemoveProfiles(ctx context.Context, ids []string) error {
request := profileRequest{Identifiers: ids}
resp, err := e.RemoveProfilesEndpoint(ctx, request)
if err != nil {
return err
}
return resp.(profileResponse).Err
}
func MakeRemoveBlueprintsEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(blueprintRequest)
@@ -58,16 +47,6 @@ func MakeRemoveBlueprintsEndpoint(svc Service) endpoint.Endpoint {
}
}
func MakeRemoveProfilesEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(profileRequest)
err = svc.RemoveProfiles(ctx, req.Identifiers)
return profileResponse{
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

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

View File

@@ -27,12 +27,6 @@ func MakeHTTPHandlers(ctx context.Context, endpoint Endpoints, opts ...httptrans
encodeResponse,
opts...,
),
ProfileHandler: httptransport.NewServer(
endpoint.RemoveProfilesEndpoint,
decodeProfileRequest,
encodeResponse,
opts...,
),
UnblockDeviceHandler: httptransport.NewServer(
endpoint.UnblockDeviceEndpoint,
decodeUnblockDeviceRequest,

View File

@@ -18,13 +18,13 @@ const (
type DB struct {
*bolt.DB
profDB *profile.DB
profDB profile.Store
userDB *user.DB
}
func NewDB(
db *bolt.DB,
profileDB *profile.DB,
profileDB profile.Store,
userDB *user.DB,
) (*DB, error) {
err := db.Update(func(tx *bolt.Tx) error {

View File

@@ -0,0 +1,59 @@
package profile
import (
"context"
"encoding/json"
"net/http"
"github.com/go-kit/kit/endpoint"
)
func (svc *ProfileService) ApplyProfile(ctx context.Context, p *Profile) error {
return svc.store.Save(p)
}
type applyProfileRequest struct {
Profile *Profile `json:"profile"`
}
type applyProfileResponse struct {
Err error `json:"err,omitempty"`
}
func (r applyProfileResponse) error() error { return r.Err }
func decodeApplyProfileRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req applyProfileRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
return req, nil
}
func decodeApplyProfileResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp applyProfileResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func MakeApplyProfileEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(applyProfileRequest)
err = svc.ApplyProfile(ctx, req.Profile)
return applyProfileResponse{
Err: err,
}, nil
}
}
func (e Endpoints) ApplyProfile(ctx context.Context, p *Profile) error {
request := applyProfileRequest{Profile: p}
resp, err := e.ApplyProfileEndpoint(ctx, request)
if err != nil {
return err
}
return resp.(applyProfileResponse).Err
}

View File

@@ -1,9 +1,10 @@
package profile
package builtin
import (
"fmt"
"github.com/boltdb/bolt"
"github.com/micromdm/micromdm/platform/profile"
"github.com/pkg/errors"
)
@@ -29,15 +30,15 @@ func NewDB(db *bolt.DB) (*DB, error) {
return datastore, nil
}
func (db *DB) List() ([]Profile, error) {
func (db *DB) List() ([]profile.Profile, error) {
// TODO add filter/limit with ForEach
var list []Profile
var list []profile.Profile
err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(ProfileBucket))
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
var p Profile
if err := UnmarshalProfile(v, &p); err != nil {
var p profile.Profile
if err := profile.UnmarshalProfile(v, &p); err != nil {
return err
}
list = append(list, p)
@@ -47,7 +48,7 @@ func (db *DB) List() ([]Profile, error) {
return list, err
}
func (db *DB) Save(p *Profile) error {
func (db *DB) Save(p *profile.Profile) error {
err := p.Validate()
if err != nil {
return err
@@ -60,7 +61,7 @@ func (db *DB) Save(p *Profile) error {
if bkt == nil {
return fmt.Errorf("bucket %q not found!", ProfileBucket)
}
pproto, err := MarshalProfile(p)
pproto, err := profile.MarshalProfile(p)
if err != nil {
return errors.Wrap(err, "marshalling profile")
}
@@ -70,15 +71,15 @@ func (db *DB) Save(p *Profile) error {
return tx.Commit()
}
func (db *DB) ProfileById(id string) (*Profile, error) {
var p Profile
func (db *DB) ProfileById(id string) (*profile.Profile, error) {
var p profile.Profile
err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(ProfileBucket))
v := b.Get([]byte(id))
if v == nil {
return &notFound{"Profile", fmt.Sprintf("id %s", id)}
}
return UnmarshalProfile(v, &p)
return profile.UnmarshalProfile(v, &p)
})
return &p, err
}
@@ -104,9 +105,6 @@ func (e *notFound) Error() string {
return fmt.Sprintf("not found: %s %s", e.ResourceType, e.Message)
}
func IsNotFound(err error) bool {
if _, ok := err.(*notFound); ok {
return true
}
return false
func (e *notFound) NotFound() bool {
return true
}

View File

@@ -0,0 +1,70 @@
package profile
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 applyProfileEndpoint endpoint.Endpoint
{
applyProfileEndpoint = httptransport.NewClient(
"PUT",
copyURL(u, "/v1/profiles"),
encodeRequestWithToken(token, httptransport.EncodeJSONRequest),
decodeApplyProfileResponse,
opts...,
).Endpoint()
}
var getProfilesEndpoint endpoint.Endpoint
{
getProfilesEndpoint = httptransport.NewClient(
"GET",
copyURL(u, "/v1/profiles"),
encodeRequestWithToken(token, httptransport.EncodeJSONRequest),
decodeGetProfilesResponse,
opts...,
).Endpoint()
}
var removeProfilesEndpoint endpoint.Endpoint
{
removeProfilesEndpoint = httptransport.NewClient(
"DELETE",
copyURL(u, "/v1/profiles"),
encodeRequestWithToken(token, httptransport.EncodeJSONRequest),
decodeRemoveProfileResponse,
opts...,
).Endpoint()
}
return Endpoints{
ApplyProfileEndpoint: applyProfileEndpoint,
GetProfilesEndpoint: getProfilesEndpoint,
RemoveProfilesEndpoint: removeProfilesEndpoint,
}, 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,70 @@
package profile
import (
"context"
"encoding/json"
"net/http"
"github.com/go-kit/kit/endpoint"
)
func (svc *ProfileService) GetProfiles(ctx context.Context, opt GetProfilesOption) ([]Profile, error) {
if opt.Identifier != "" {
foundProf, err := svc.store.ProfileById(opt.Identifier)
if err != nil {
return nil, err
}
return []Profile{*foundProf}, nil
} else {
return svc.store.List()
}
}
type getProfilesRequest struct{ Opts GetProfilesOption }
type getProfilesResponse struct {
Profiles []Profile `json:"profiles"`
Err error `json:"err,omitempty"`
}
func (r getProfilesResponse) error() error { return r.Err }
func decodeGetProfilesRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var opts GetProfilesOption
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
return nil, err
}
req := getProfilesRequest{
Opts: opts,
}
return req, nil
}
func decodeGetProfilesResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp getProfilesResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func MakeGetProfilesEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(getProfilesRequest)
profiles, err := svc.GetProfiles(ctx, req.Opts)
return getProfilesResponse{
Profiles: profiles,
Err: err,
}, nil
}
}
func (e Endpoints) GetProfiles(ctx context.Context, opt GetProfilesOption) ([]Profile, error) {
request := getProfilesRequest{opt}
response, err := e.GetProfilesEndpoint(ctx, request.Opts)
if err != nil {
return nil, err
}
return response.(getProfilesResponse).Profiles, response.(getProfilesResponse).Err
}

View File

@@ -0,0 +1,65 @@
package profile
import (
"context"
"encoding/json"
"net/http"
"github.com/go-kit/kit/endpoint"
)
func (svc *ProfileService) RemoveProfiles(ctx context.Context, ids []string) error {
for _, id := range ids {
err := svc.store.Delete(id)
if err != nil {
return err
}
}
return nil
}
type removeProfileRequest struct {
Identifiers []string `json:"ids"`
}
type removeProfileResponse struct {
Err error `json:"err,omitempty"`
}
func (r removeProfileResponse) error() error { return r.Err }
func decodeRemoveProfilesRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req removeProfileRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
return req, nil
}
func decodeRemoveProfileResponse(_ context.Context, r *http.Response) (interface{}, error) {
if r.StatusCode != http.StatusOK {
return nil, errorDecoder(r)
}
var resp removeProfileResponse
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func MakeRemoveProfilesEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(removeProfileRequest)
err = svc.RemoveProfiles(ctx, req.Identifiers)
return removeProfileResponse{
Err: err,
}, nil
}
}
func (e Endpoints) RemoveProfiles(ctx context.Context, ids []string) error {
request := removeProfileRequest{Identifiers: ids}
resp, err := e.RemoveProfilesEndpoint(ctx, request)
if err != nil {
return err
}
return resp.(removeProfileResponse).Err
}

View File

@@ -0,0 +1,77 @@
package profile
import (
"encoding/json"
"errors"
"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"
)
type Endpoints struct {
ApplyProfileEndpoint endpoint.Endpoint
GetProfilesEndpoint endpoint.Endpoint
RemoveProfilesEndpoint endpoint.Endpoint
}
func MakeServerEndpoints(s Service) Endpoints {
return Endpoints{
ApplyProfileEndpoint: MakeApplyProfileEndpoint(s),
GetProfilesEndpoint: MakeGetProfilesEndpoint(s),
RemoveProfilesEndpoint: MakeRemoveProfilesEndpoint(s),
}
}
func MakeHTTPHandler(e Endpoints, logger log.Logger) http.Handler {
options := []httptransport.ServerOption{
httptransport.ServerErrorLogger(logger),
}
r := mux.NewRouter()
// GET /v1/profiles get a list of profiles managed by the server
// PUT /v1/profiles create or replace a profile on the server
// DELETE /v1/profiles remove one or more profiles from the server
r.Methods("GET").Path("/v1/profiles").Handler(httptransport.NewServer(
e.GetProfilesEndpoint,
decodeGetProfilesRequest,
httptransport.EncodeJSONResponse,
options...,
))
r.Methods("PUT").Path("/v1/profiles").Handler(httptransport.NewServer(
e.ApplyProfileEndpoint,
decodeApplyProfileRequest,
httptransport.EncodeJSONResponse,
options...,
))
r.Methods("DELETE").Path("/v1/profiles").Handler(httptransport.NewServer(
e.RemoveProfilesEndpoint,
decodeRemoveProfilesRequest,
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,40 @@
package profile
import (
"context"
)
type Service interface {
ApplyProfile(ctx context.Context, p *Profile) error
GetProfiles(ctx context.Context, opt GetProfilesOption) ([]Profile, error)
RemoveProfiles(ctx context.Context, ids []string) error
}
type GetProfilesOption struct {
Identifier string `json:"id"`
}
type Store interface {
ProfileById(id string) (*Profile, error)
Save(p *Profile) error
List() ([]Profile, error)
Delete(id string) error
}
func New(store Store) *ProfileService {
return &ProfileService{store: store}
}
type ProfileService struct {
store Store
}
func IsNotFound(err error) bool {
type notFoundError interface {
error
NotFound() bool
}
_, ok := err.(notFoundError)
return ok
}