mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-06 09:16:24 +08:00
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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
59
cmd/mdmctl/setup.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
59
platform/profile/apply_profile.go
Normal file
59
platform/profile/apply_profile.go
Normal 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
|
||||
}
|
||||
@@ -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 ¬Found{"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
|
||||
}
|
||||
70
platform/profile/client.go
Normal file
70
platform/profile/client.go
Normal 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
|
||||
}
|
||||
70
platform/profile/get_profiles.go
Normal file
70
platform/profile/get_profiles.go
Normal 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
|
||||
}
|
||||
65
platform/profile/remove_profiles.go
Normal file
65
platform/profile/remove_profiles.go
Normal 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
|
||||
}
|
||||
77
platform/profile/server.go
Normal file
77
platform/profile/server.go
Normal 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)
|
||||
}
|
||||
40
platform/profile/service.go
Normal file
40
platform/profile/service.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user