mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-13 14:05:42 +08:00
Define new datastore for retrieving installed applications by device uuid
Add InstalledApps method to management service Add endpoint for installed applications at /management/v1/devices/uuid/applications
This commit is contained in:
14
applications/application.go
Normal file
14
applications/application.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package applications
|
||||||
|
|
||||||
|
type Application struct {
|
||||||
|
Identifier string `plist:",omitempty" json:"identifier,omitempty"`
|
||||||
|
Version string `plist:",omitempty" json:"version,omitempty"`
|
||||||
|
ShortVersion string `plist:",omitempty" json:"short_version,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
BundleSize int `plist:",omitempty" json:"bundle_size,omitempty"`
|
||||||
|
|
||||||
|
// The size of the app's document, library, and other folders, in bytes.
|
||||||
|
DynamicSize int `plist:",omitempty" json:"dynamic_size,omitempty"`
|
||||||
|
|
||||||
|
IsValidated bool `plist:",omitempty" json:"is_validated,omitempty"`
|
||||||
|
}
|
||||||
60
applications/datastore.go
Normal file
60
applications/datastore.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package applications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
kitlog "github.com/go-kit/kit/log"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
_ "github.com/lib/pq" // postgres driver
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Datastore manages devices in a database
|
||||||
|
type Datastore interface {
|
||||||
|
GetApplicationsByDeviceUUID(deviceUUID string) (*[]Application, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pgStore struct {
|
||||||
|
*sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDB(driver, conn string, logger kitlog.Logger) (Datastore, error) {
|
||||||
|
switch driver {
|
||||||
|
case "postgres":
|
||||||
|
db, err := sqlx.Open(driver, conn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "device datastore")
|
||||||
|
}
|
||||||
|
var dbError error
|
||||||
|
maxAttempts := 20
|
||||||
|
for attempts := 1; attempts <= maxAttempts; attempts++ {
|
||||||
|
dbError = db.Ping()
|
||||||
|
if dbError == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
logger.Log("msg", fmt.Sprintf("could not connect to postgres: %v", dbError))
|
||||||
|
time.Sleep(time.Duration(attempts) * time.Second)
|
||||||
|
}
|
||||||
|
if dbError != nil {
|
||||||
|
return nil, errors.Wrap(dbError, "device datastore")
|
||||||
|
}
|
||||||
|
return pgStore{DB: db}, nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unknown driver")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store pgStore) GetApplicationsByDeviceUUID(deviceUUID string) (*[]Application, error) {
|
||||||
|
apps := []Application{}
|
||||||
|
query := `SELECT * FROM applications
|
||||||
|
RIGHT JOIN devices_applications ON applications.application_uuid = devices_applications.application_uuid
|
||||||
|
WHERE devices_applications.device_uuid=$1`
|
||||||
|
|
||||||
|
err := store.Select(&apps, query, deviceUUID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apps, nil
|
||||||
|
}
|
||||||
1
applications/datastore_test.go
Normal file
1
applications/datastore_test.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package applications
|
||||||
13
main.go
13
main.go
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/RobotsAndPencils/buford/push"
|
"github.com/RobotsAndPencils/buford/push"
|
||||||
"github.com/go-kit/kit/log"
|
"github.com/go-kit/kit/log"
|
||||||
"github.com/micromdm/dep"
|
"github.com/micromdm/dep"
|
||||||
|
"github.com/micromdm/micromdm/applications"
|
||||||
"github.com/micromdm/micromdm/checkin"
|
"github.com/micromdm/micromdm/checkin"
|
||||||
"github.com/micromdm/micromdm/command"
|
"github.com/micromdm/micromdm/command"
|
||||||
"github.com/micromdm/micromdm/connect"
|
"github.com/micromdm/micromdm/connect"
|
||||||
@@ -184,8 +185,18 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appsDB, err := applications.NewDB(
|
||||||
|
"postgres",
|
||||||
|
*flPGconn,
|
||||||
|
logger,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log("err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
dc := depClient(logger, *flDEPCK, *flDEPCS, *flDEPAT, *flDEPAS, *flDEPServerURL, *flDEPsim)
|
dc := depClient(logger, *flDEPCK, *flDEPCS, *flDEPAT, *flDEPAS, *flDEPServerURL, *flDEPsim)
|
||||||
mgmtSvc := management.NewService(deviceDB, workflowDB, dc, pushSvc)
|
mgmtSvc := management.NewService(deviceDB, workflowDB, dc, pushSvc, appsDB)
|
||||||
commandSvc := command.NewService(commandDB)
|
commandSvc := command.NewService(commandDB)
|
||||||
checkinSvc := checkin.NewService(deviceDB, mgmtSvc, commandSvc, enrollmentProfile)
|
checkinSvc := checkin.NewService(deviceDB, mgmtSvc, commandSvc, enrollmentProfile)
|
||||||
connectSvc := connect.NewService(deviceDB, commandSvc)
|
connectSvc := connect.NewService(deviceDB, commandSvc)
|
||||||
|
|||||||
27
management/endpoint_installedapps.go
Normal file
27
management/endpoint_installedapps.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-kit/kit/endpoint"
|
||||||
|
"github.com/micromdm/micromdm/applications"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type installedAppsRequest struct {
|
||||||
|
UUID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type installedAppsResponse struct {
|
||||||
|
applications []applications.Application
|
||||||
|
Err error `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeInstalledAppsEndpoint(svc Service) endpoint.Endpoint {
|
||||||
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||||
|
req := request.(installedAppsRequest)
|
||||||
|
apps, err := svc.InstalledApps(req.UUID)
|
||||||
|
if err != nil {
|
||||||
|
return installedAppsResponse{Err: err}, nil
|
||||||
|
}
|
||||||
|
return installedAppsResponse{applications: *apps}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/RobotsAndPencils/buford/payload"
|
"github.com/RobotsAndPencils/buford/payload"
|
||||||
"github.com/RobotsAndPencils/buford/push"
|
"github.com/RobotsAndPencils/buford/push"
|
||||||
"github.com/micromdm/dep"
|
"github.com/micromdm/dep"
|
||||||
|
"github.com/micromdm/micromdm/applications"
|
||||||
"github.com/micromdm/micromdm/device"
|
"github.com/micromdm/micromdm/device"
|
||||||
"github.com/micromdm/micromdm/workflow"
|
"github.com/micromdm/micromdm/workflow"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -26,6 +27,10 @@ type Service interface {
|
|||||||
// Devices
|
// Devices
|
||||||
Devices() ([]device.Device, error)
|
Devices() ([]device.Device, error)
|
||||||
Device(uuid string) (*device.Device, error)
|
Device(uuid string) (*device.Device, error)
|
||||||
|
|
||||||
|
// Installed Applications
|
||||||
|
InstalledApps(deviceUUID string) (*[]applications.Application, error)
|
||||||
|
|
||||||
// AssignWorkflow assigns a workflow to a device
|
// AssignWorkflow assigns a workflow to a device
|
||||||
AssignWorkflow(deviceUUID, workflowUUID string) error
|
AssignWorkflow(deviceUUID, workflowUUID string) error
|
||||||
|
|
||||||
@@ -38,20 +43,22 @@ type Service interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewService creates a management service
|
// NewService creates a management service
|
||||||
func NewService(ds device.Datastore, ws workflow.Datastore, dc dep.Client, ps *push.Service) Service {
|
func NewService(ds device.Datastore, ws workflow.Datastore, dc dep.Client, ps *push.Service, as applications.Datastore) Service {
|
||||||
return &service{
|
return &service{
|
||||||
devices: ds,
|
devices: ds,
|
||||||
depClient: dc,
|
depClient: dc,
|
||||||
workflows: ws,
|
workflows: ws,
|
||||||
pushsvc: ps,
|
pushsvc: ps,
|
||||||
|
applications: as,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
depClient dep.Client
|
depClient dep.Client
|
||||||
devices device.Datastore
|
devices device.Datastore
|
||||||
workflows workflow.Datastore
|
workflows workflow.Datastore
|
||||||
pushsvc *push.Service
|
pushsvc *push.Service
|
||||||
|
applications applications.Datastore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc service) Push(deviceUDID string) (string, error) {
|
func (svc service) Push(deviceUDID string) (string, error) {
|
||||||
@@ -157,3 +164,12 @@ func (svc service) AssignWorkflow(deviceUUID, workflowUUID string) error {
|
|||||||
dev.Workflow = workflowUUID
|
dev.Workflow = workflowUUID
|
||||||
return svc.devices.Save("assignWorkflow", dev)
|
return svc.devices.Save("assignWorkflow", dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc service) InstalledApps(deviceUUID string) (*[]applications.Application, error) {
|
||||||
|
apps, err := svc.applications.GetApplicationsByDeviceUUID(deviceUUID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "management: installed apps")
|
||||||
|
}
|
||||||
|
|
||||||
|
return apps, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -101,6 +101,13 @@ func ServiceHandler(ctx context.Context, svc Service, logger kitlog.Logger) http
|
|||||||
encodeResponse,
|
encodeResponse,
|
||||||
opts...,
|
opts...,
|
||||||
)
|
)
|
||||||
|
installedAppsHandler := kithttp.NewServer(
|
||||||
|
ctx,
|
||||||
|
makeInstalledAppsEndpoint(svc),
|
||||||
|
decodeInstalledAppsRequest,
|
||||||
|
encodeResponse,
|
||||||
|
opts...,
|
||||||
|
)
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
|
|
||||||
@@ -111,6 +118,7 @@ func ServiceHandler(ctx context.Context, svc Service, logger kitlog.Logger) http
|
|||||||
r.Handle("/management/v1/devices/{uuid}", showDeviceHandler).Methods("GET")
|
r.Handle("/management/v1/devices/{uuid}", showDeviceHandler).Methods("GET")
|
||||||
r.Handle("/management/v1/devices/{uuid}", updateDeviceHandler).Methods("PATCH")
|
r.Handle("/management/v1/devices/{uuid}", updateDeviceHandler).Methods("PATCH")
|
||||||
r.Handle("/management/v1/devices/{udid}/push", pushHandler).Methods("POST")
|
r.Handle("/management/v1/devices/{udid}/push", pushHandler).Methods("POST")
|
||||||
|
r.Handle("/management/v1/devices/{uuid}/applications", installedAppsHandler).Methods("GET")
|
||||||
// profiles
|
// profiles
|
||||||
r.Handle("/management/v1/profiles", addProfileHandler).Methods("POST")
|
r.Handle("/management/v1/profiles", addProfileHandler).Methods("POST")
|
||||||
r.Handle("/management/v1/profiles", listProfilesHandler).Methods("GET")
|
r.Handle("/management/v1/profiles", listProfilesHandler).Methods("GET")
|
||||||
@@ -223,6 +231,21 @@ func decodeUpdateDeviceRequest(_ context.Context, r *http.Request) (interface{},
|
|||||||
return request, nil
|
return request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeInstalledAppsRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
deviceUUID, ok := vars["uuid"]
|
||||||
|
if !ok {
|
||||||
|
return nil, errBadRouting
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = installedAppsRequest{UUID: deviceUUID}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&request)
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil, errEmptyRequest
|
||||||
|
}
|
||||||
|
return request, nil
|
||||||
|
}
|
||||||
|
|
||||||
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
|
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
|
||||||
if e, ok := response.(errorer); ok && e.error() != nil {
|
if e, ok := response.(errorer); ok && e.error() != nil {
|
||||||
encodeError(ctx, e.error(), w)
|
encodeError(ctx, e.error(), w)
|
||||||
|
|||||||
Reference in New Issue
Block a user