mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-13 05:45:41 +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/go-kit/kit/log"
|
||||
"github.com/micromdm/dep"
|
||||
"github.com/micromdm/micromdm/applications"
|
||||
"github.com/micromdm/micromdm/checkin"
|
||||
"github.com/micromdm/micromdm/command"
|
||||
"github.com/micromdm/micromdm/connect"
|
||||
@@ -184,8 +185,18 @@ func main() {
|
||||
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)
|
||||
mgmtSvc := management.NewService(deviceDB, workflowDB, dc, pushSvc)
|
||||
mgmtSvc := management.NewService(deviceDB, workflowDB, dc, pushSvc, appsDB)
|
||||
commandSvc := command.NewService(commandDB)
|
||||
checkinSvc := checkin.NewService(deviceDB, mgmtSvc, commandSvc, enrollmentProfile)
|
||||
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/push"
|
||||
"github.com/micromdm/dep"
|
||||
"github.com/micromdm/micromdm/applications"
|
||||
"github.com/micromdm/micromdm/device"
|
||||
"github.com/micromdm/micromdm/workflow"
|
||||
"github.com/pkg/errors"
|
||||
@@ -26,6 +27,10 @@ type Service interface {
|
||||
// Devices
|
||||
Devices() ([]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(deviceUUID, workflowUUID string) error
|
||||
|
||||
@@ -38,20 +43,22 @@ type Service interface {
|
||||
}
|
||||
|
||||
// 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{
|
||||
devices: ds,
|
||||
depClient: dc,
|
||||
workflows: ws,
|
||||
pushsvc: ps,
|
||||
devices: ds,
|
||||
depClient: dc,
|
||||
workflows: ws,
|
||||
pushsvc: ps,
|
||||
applications: as,
|
||||
}
|
||||
}
|
||||
|
||||
type service struct {
|
||||
depClient dep.Client
|
||||
devices device.Datastore
|
||||
workflows workflow.Datastore
|
||||
pushsvc *push.Service
|
||||
depClient dep.Client
|
||||
devices device.Datastore
|
||||
workflows workflow.Datastore
|
||||
pushsvc *push.Service
|
||||
applications applications.Datastore
|
||||
}
|
||||
|
||||
func (svc service) Push(deviceUDID string) (string, error) {
|
||||
@@ -157,3 +164,12 @@ func (svc service) AssignWorkflow(deviceUUID, workflowUUID string) error {
|
||||
dev.Workflow = workflowUUID
|
||||
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,
|
||||
opts...,
|
||||
)
|
||||
installedAppsHandler := kithttp.NewServer(
|
||||
ctx,
|
||||
makeInstalledAppsEndpoint(svc),
|
||||
decodeInstalledAppsRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
)
|
||||
|
||||
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}", updateDeviceHandler).Methods("PATCH")
|
||||
r.Handle("/management/v1/devices/{udid}/push", pushHandler).Methods("POST")
|
||||
r.Handle("/management/v1/devices/{uuid}/applications", installedAppsHandler).Methods("GET")
|
||||
// profiles
|
||||
r.Handle("/management/v1/profiles", addProfileHandler).Methods("POST")
|
||||
r.Handle("/management/v1/profiles", listProfilesHandler).Methods("GET")
|
||||
@@ -223,6 +231,21 @@ func decodeUpdateDeviceRequest(_ context.Context, r *http.Request) (interface{},
|
||||
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 {
|
||||
if e, ok := response.(errorer); ok && e.error() != nil {
|
||||
encodeError(ctx, e.error(), w)
|
||||
|
||||
Reference in New Issue
Block a user