Profile service/store, API, and mdmctl management (#156)

* Profile service/store, API, and mdmctl management
* Group methods with their types
* Centralize error checking and remove profile ID specification on upload (unnecessary)
* Move more error checking into methods
This commit is contained in:
Jesse Peterson
2017-05-17 00:19:26 -07:00
committed by GitHub
parent 1cf4e86d8a
commit 670b4399db
16 changed files with 524 additions and 3 deletions

View File

@@ -14,6 +14,7 @@ import (
httptransport "github.com/go-kit/kit/transport/http"
"github.com/micromdm/micromdm/blueprint"
"github.com/micromdm/micromdm/core/apply"
"github.com/micromdm/micromdm/profile"
uuid "github.com/satori/go.uuid"
)
@@ -51,6 +52,8 @@ func (cmd *applyCommand) Run(args []string) error {
run = cmd.applyBlueprint
case "dep-tokens":
run = cmd.applyDEPTokens
case "profiles":
run = cmd.applyProfile
default:
cmd.Usage()
os.Exit(1)
@@ -65,6 +68,7 @@ Apply a resource.
Valid resource types:
* blueprints
* profiles
* dep-tokens
Examples:
@@ -162,3 +166,42 @@ func (cmd *applyCommand) applyDEPTokens(args []string) error {
fmt.Println("imported DEP token")
return nil
}
func (cmd *applyCommand) applyProfile(args []string) error {
flagset := flag.NewFlagSet("profiles", flag.ExitOnError)
var (
flProfilePath = flagset.String("f", "", "filename of profile to apply")
)
flagset.Usage = usageFor(flagset, "mdmctl apply profiles [flags]")
if err := flagset.Parse(args); err != nil {
return err
}
if *flProfilePath == "" {
return errors.New("must provide -f parameter")
}
if _, err := os.Stat(*flProfilePath); os.IsNotExist(err) {
return err
}
profileBytes, err := ioutil.ReadFile(*flProfilePath)
if err != nil {
return err
}
// TODO: to consider just uploading the Mobileconfig data (without a
// Profile struct and doing init server side)
var p profile.Profile
p.Mobileconfig = profileBytes
p.Identifier, err = p.Mobileconfig.GetPayloadIdentifier()
if err != nil {
return err
}
ctx := context.Background()
err = cmd.applysvc.ApplyProfile(ctx, &p)
if err != nil {
return err
}
fmt.Println(fmt.Sprintf("applied blueprint id %s from %s", p.Identifier, *flProfilePath))
return nil
}

View File

@@ -55,6 +55,8 @@ func (cmd *getCommand) Run(args []string) error {
run = cmd.getDepTokens
case "blueprints":
run = cmd.getBlueprints
case "profiles":
run = cmd.getProfiles
default:
cmd.Usage()
os.Exit(1)
@@ -72,6 +74,7 @@ Valid resource types:
* devices
* blueprints
* dep-tokens
* profiles
Examples:
# Get a list of devices
@@ -235,3 +238,53 @@ func (cmd *getCommand) getBlueprints(args []string) error {
return nil
}
func (cmd *getCommand) getProfiles(args []string) error {
flagset := flag.NewFlagSet("profiles", flag.ExitOnError)
var (
flProfilePath = flagset.String("f", "", "filename of profile to write")
flIdentifier = flagset.String("id", "", "profile Identifier")
)
flagset.Usage = usageFor(flagset, "mdmctl get blueprints [flags]")
if err := flagset.Parse(args); err != nil {
return err
}
ctx := context.Background()
profiles, err := cmd.list.GetProfiles(ctx, list.GetProfilesOption{Identifier: *flIdentifier})
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0)
fmt.Fprintf(w, "Identifier\tLength\n")
for _, p := range profiles {
fmt.Fprintf(
w,
"%s\t%d\n",
p.Identifier,
len(p.Mobileconfig),
)
}
w.Flush()
if *flIdentifier != "" && *flProfilePath != "" {
p := profiles[0]
newProfileFile, err := os.Create(*flProfilePath)
if err != nil {
return err
}
defer newProfileFile.Close()
_, err = newProfileFile.Write([]byte(p.Mobileconfig))
if err != nil {
return err
}
fmt.Printf("\nwrote profile id %s to: %s\n", p.Identifier, *flProfilePath)
if len(profiles) > 1 {
fmt.Println("WARNING: more than one Profile returned; only saved first")
}
}
return nil
}

View File

@@ -36,10 +36,21 @@ 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),
DecodeProfileRequest,
opts...,
).Endpoint()
}
return Endpoints{
ApplyBlueprintEndpoint: applyBlueprintEndpoint,
ApplyDEPTokensEndpoint: applyDEPTokensEndpoint,
ApplyProfileEndpoint: applyProfileEndpoint,
}, nil
}

View File

@@ -5,11 +5,13 @@ import (
"github.com/go-kit/kit/endpoint"
"github.com/micromdm/micromdm/blueprint"
"github.com/micromdm/micromdm/profile"
)
type Endpoints struct {
ApplyBlueprintEndpoint endpoint.Endpoint
ApplyDEPTokensEndpoint endpoint.Endpoint
ApplyProfileEndpoint endpoint.Endpoint
}
func (e Endpoints) ApplyBlueprint(ctx context.Context, bp *blueprint.Blueprint) error {
@@ -30,6 +32,15 @@ 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)
@@ -50,6 +61,16 @@ 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
}
}
type blueprintRequest struct {
Blueprint *blueprint.Blueprint `json:"blueprint"`
}
@@ -58,6 +79,18 @@ type blueprintResponse struct {
Err error `json:"err,omitempty"`
}
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"`
}
@@ -67,4 +100,3 @@ type depTokensResponse struct {
}
func (r depTokensResponse) error() error { return r.Err }
func (r blueprintResponse) error() error { return r.Err }

View File

@@ -15,15 +15,18 @@ import (
"github.com/boltdb/bolt"
"github.com/micromdm/micromdm/blueprint"
"github.com/micromdm/micromdm/core/list"
"github.com/micromdm/micromdm/profile"
)
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
}
type ApplyService struct {
Blueprints *blueprint.DB
Profiles *profile.DB
DB *bolt.DB // TODO: replace with reference to DEP token svc/pkg
}
@@ -115,3 +118,7 @@ func (svc *ApplyService) ApplyDEPToken(ctx context.Context, P7MContent []byte) e
fmt.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

@@ -14,6 +14,7 @@ import (
type HTTPHandlers struct {
BlueprintHandler http.Handler
DEPTokensHandler http.Handler
ProfileHandler http.Handler
}
func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptransport.ServerOption) HTTPHandlers {
@@ -30,6 +31,12 @@ func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptran
encodeResponse,
opts...,
),
ProfileHandler: httptransport.NewServer(
endpoints.ApplyProfileEndpoint,
decodeProfileRequest,
encodeResponse,
opts...,
),
}
return h
}
@@ -50,6 +57,14 @@ 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
}
type errorWrapper struct {
Error string `json:"error"`
}
@@ -112,3 +127,12 @@ func DecodeDEPTokensRequest(_ context.Context, r *http.Response) (interface{}, e
err := json.NewDecoder(r.Body).Decode(&resp)
return resp, err
}
func DecodeProfileRequest(_ 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
}

View File

@@ -45,11 +45,21 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
DecodeGetBlueprintsResponse,
).Endpoint()
}
var getProfilesEndpoint endpoint.Endpoint
{
getProfilesEndpoint = httptransport.NewClient(
"GET",
copyURL(u, "/v1/profiles"),
encodeRequestWithToken(token, EncodeHTTPGenericRequest),
DecodeGetProfilesResponse,
).Endpoint()
}
return Endpoints{
ListDevicesEndpoint: listDevicesEndpoint,
GetDEPTokensEndpoint: getDEPTokensEndpoint,
GetBlueprintsEndpoint: getBlueprintsEndpoint,
GetProfilesEndpoint: getProfilesEndpoint,
}, nil
}

View File

@@ -6,12 +6,14 @@ import (
"github.com/go-kit/kit/endpoint"
"github.com/micromdm/micromdm/blueprint"
"github.com/micromdm/micromdm/profile"
)
type Endpoints struct {
ListDevicesEndpoint endpoint.Endpoint
GetDEPTokensEndpoint endpoint.Endpoint
GetBlueprintsEndpoint endpoint.Endpoint
GetProfilesEndpoint endpoint.Endpoint
}
func (e Endpoints) ListDevices(ctx context.Context, opts ListDevicesOption) ([]DeviceDTO, error) {
@@ -40,6 +42,15 @@ 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 MakeListDevicesEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(devicesRequest)
@@ -73,6 +84,17 @@ 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
}
}
type DeviceDTO struct {
SerialNumber string `json:"serial_number"`
UDID string `json:"udid"`
@@ -107,3 +129,11 @@ 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 }

View File

@@ -13,6 +13,7 @@ import (
"github.com/micromdm/micromdm/blueprint"
"github.com/micromdm/micromdm/crypto"
"github.com/micromdm/micromdm/device"
"github.com/micromdm/micromdm/profile"
)
type ListDevicesOption struct {
@@ -27,15 +28,21 @@ type GetBlueprintsOption struct {
FilterName string
}
type GetProfilesOption struct {
Identifier string `json:"id"`
}
type Service interface {
ListDevices(ctx context.Context, opt ListDevicesOption) ([]DeviceDTO, error)
GetDEPTokens(ctx context.Context) ([]DEPToken, []byte, error)
GetBlueprints(ctx context.Context, opt GetBlueprintsOption) ([]blueprint.Blueprint, error)
GetProfiles(ctx context.Context, opt GetProfilesOption) ([]profile.Profile, error)
}
type ListService struct {
Devices *device.DB
Blueprints *blueprint.DB
Profiles *profile.DB
DB *bolt.DB // TODO: replace with reference to DEP token svc/pkg
}
@@ -176,3 +183,15 @@ 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,6 +15,7 @@ type HTTPHandlers struct {
ListDevicesHandler http.Handler
GetDEPTokensHandler http.Handler
GetBlueprintsHandler http.Handler
GetProfilesHandler http.Handler
}
func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptransport.ServerOption) HTTPHandlers {
@@ -35,6 +36,11 @@ func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptran
decodeGetBlueprintsRequest,
encodeResponse,
opts...),
GetProfilesHandler: httptransport.NewServer(
endpoints.GetProfilesEndpoint,
decodeGetProfilesRequest,
encodeResponse,
opts...),
}
return h
}
@@ -61,6 +67,17 @@ 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 errorDecoder(r *http.Response) error {
var w errorWrapper
if err := json.NewDecoder(r.Body).Decode(&w); err != nil {
@@ -132,3 +149,12 @@ func DecodeGetBlueprintsResponse(_ context.Context, r *http.Response) (interface
err := json.NewDecoder(r.Body).Decode(&resp)
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
}

100
profile/db.go Normal file
View File

@@ -0,0 +1,100 @@
package profile
import (
"fmt"
"github.com/boltdb/bolt"
"github.com/pkg/errors"
)
const (
ProfileBucket = "mdm.Profile"
)
type DB struct {
*bolt.DB
}
func NewDB(db *bolt.DB) (*DB, error) {
err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(ProfileBucket))
return err
})
if err != nil {
return nil, errors.Wrapf(err, "creating %s bucket", ProfileBucket)
}
datastore := &DB{
DB: db,
}
return datastore, nil
}
func (db *DB) List() ([]Profile, error) {
// TODO add filter/limit with ForEach
var list []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 {
return err
}
list = append(list, p)
}
return nil
})
return list, err
}
func (db *DB) Save(p *Profile) error {
err := p.Validate()
if err != nil {
return err
}
tx, err := db.DB.Begin(true)
if err != nil {
return errors.Wrap(err, "begin transaction")
}
bkt := tx.Bucket([]byte(ProfileBucket))
if bkt == nil {
return fmt.Errorf("bucket %q not found!", ProfileBucket)
}
pproto, err := MarshalProfile(p)
if err != nil {
return errors.Wrap(err, "marshalling profile")
}
if err := bkt.Put([]byte(p.Identifier), pproto); err != nil {
return errors.Wrap(err, "put profile to boltdb")
}
return tx.Commit()
}
func (db *DB) ProfileById(id string) (*Profile, error) {
var p 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 &p, err
}
type notFound struct {
ResourceType string
Message string
}
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
}

View File

@@ -0,0 +1,3 @@
package profileproto
//go:generate protoc --go_out=. profile.proto

View File

@@ -0,0 +1,70 @@
// Code generated by protoc-gen-go.
// source: profile.proto
// DO NOT EDIT!
/*
Package profileproto is a generated protocol buffer package.
It is generated from these files:
profile.proto
It has these top-level messages:
Profile
*/
package profileproto
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Profile struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Mobileconfig []byte `protobuf:"bytes,2,opt,name=mobileconfig,proto3" json:"mobileconfig,omitempty"`
}
func (m *Profile) Reset() { *m = Profile{} }
func (m *Profile) String() string { return proto.CompactTextString(m) }
func (*Profile) ProtoMessage() {}
func (*Profile) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Profile) GetId() string {
if m != nil {
return m.Id
}
return ""
}
func (m *Profile) GetMobileconfig() []byte {
if m != nil {
return m.Mobileconfig
}
return nil
}
func init() {
proto.RegisterType((*Profile)(nil), "profileproto.Profile")
}
func init() { proto.RegisterFile("profile.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 97 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0x28, 0xca, 0x4f,
0xcb, 0xcc, 0x49, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x81, 0x72, 0xc1, 0x3c, 0x25,
0x5b, 0x2e, 0xf6, 0x00, 0x08, 0x5f, 0x88, 0x8f, 0x8b, 0x29, 0x33, 0x45, 0x82, 0x51, 0x81, 0x51,
0x83, 0x33, 0x88, 0x29, 0x33, 0x45, 0x48, 0x89, 0x8b, 0x27, 0x37, 0x3f, 0x29, 0x33, 0x27, 0x35,
0x39, 0x3f, 0x2f, 0x2d, 0x33, 0x5d, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0x45, 0x2c, 0x89,
0x0d, 0x6c, 0x8a, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xea, 0x33, 0x2f, 0xfa, 0x64, 0x00, 0x00,
0x00,
}

View File

@@ -0,0 +1,8 @@
syntax = "proto3";
package profileproto;
message Profile {
string id = 1;
bytes mobileconfig = 2;
}

70
profile/profile.go Normal file
View File

@@ -0,0 +1,70 @@
package profile
import (
"errors"
"github.com/gogo/protobuf/proto"
"github.com/groob/plist"
"github.com/micromdm/micromdm/profile/internal/profileproto"
)
type Mobileconfig []byte
// only used to parse plists to get the PayloadIdentifier
type payloadIdentifier struct {
PayloadIdentifier string
}
func (mc *Mobileconfig) GetPayloadIdentifier() (string, error) {
// TODO: support CMS signed profiles
var pId payloadIdentifier
err := plist.Unmarshal(*mc, &pId)
if err != nil {
return "", err
}
if pId.PayloadIdentifier == "" {
return "", errors.New("empty PayloadIdentifier in profile")
}
return pId.PayloadIdentifier, err
}
type Profile struct {
Identifier string
Mobileconfig Mobileconfig
}
// Validate checks the internal consistency and validity of a Profile structure
func (p *Profile) Validate() error {
if p.Identifier == "" {
return errors.New("Profile struct must have Identifier")
}
if len(p.Mobileconfig) < 1 {
return errors.New("no Mobileconfig data")
}
payloadId, err := p.Mobileconfig.GetPayloadIdentifier()
if err != nil {
return err
}
if payloadId != p.Identifier {
return errors.New("payload Identifier does not match Profile")
}
return nil
}
func MarshalProfile(p *Profile) ([]byte, error) {
protobp := profileproto.Profile{
Id: p.Identifier,
Mobileconfig: p.Mobileconfig,
}
return proto.Marshal(&protobp)
}
func UnmarshalProfile(data []byte, p *Profile) error {
var pb profileproto.Profile
if err := proto.Unmarshal(data, &pb); err != nil {
return err
}
p.Identifier = pb.GetId()
p.Mobileconfig = pb.GetMobileconfig()
return nil
}

View File

@@ -50,6 +50,7 @@ import (
"github.com/micromdm/micromdm/depsync"
"github.com/micromdm/micromdm/device"
"github.com/micromdm/micromdm/enroll"
"github.com/micromdm/micromdm/profile"
"github.com/micromdm/micromdm/pubsub"
nanopush "github.com/micromdm/micromdm/push"
"github.com/micromdm/micromdm/queue"
@@ -151,6 +152,11 @@ func serve(args []string) error {
stdlog.Fatal(err)
}
profDB, err := profile.NewDB(sm.db)
if err != nil {
stdlog.Fatal(err)
}
ctx := context.Background()
httpLogger := log.With(logger, "transport", "http")
var checkinEndpoint endpoint.Endpoint
@@ -192,7 +198,7 @@ func serve(args []string) error {
var listsvc list.Service
{
listsvc = &list.ListService{Devices: devDB, DB: sm.db, Blueprints: bpDB}
listsvc = &list.ListService{Devices: devDB, DB: sm.db, Blueprints: bpDB, Profiles: profDB}
}
var listDevicesEndpoint endpoint.Endpoint
{
@@ -203,11 +209,12 @@ func serve(args []string) error {
ListDevicesEndpoint: listDevicesEndpoint,
GetDEPTokensEndpoint: list.MakeGetDEPTokensEndpoint(listsvc),
GetBlueprintsEndpoint: list.MakeGetBlueprintsEndpoint(listsvc),
GetProfilesEndpoint: list.MakeGetProfilesEndpoint(listsvc),
}
var applysvc apply.Service
{
applysvc = &apply.ApplyService{Blueprints: bpDB, DB: sm.db}
applysvc = &apply.ApplyService{Blueprints: bpDB, DB: sm.db, Profiles: profDB}
}
var applyBlueprintEndpoint endpoint.Endpoint
@@ -215,9 +222,15 @@ func serve(args []string) error {
applyBlueprintEndpoint = apply.MakeApplyBlueprintEndpoint(applysvc)
}
var applyProfileEndpoint endpoint.Endpoint
{
applyProfileEndpoint = apply.MakeApplyProfileEndpoint(applysvc)
}
applyEndpoints := apply.Endpoints{
ApplyBlueprintEndpoint: applyBlueprintEndpoint,
ApplyDEPTokensEndpoint: apply.MakeApplyDEPTokensEndpoint(applysvc),
ApplyProfileEndpoint: applyProfileEndpoint,
}
applyAPIHandlers := apply.MakeHTTPHandlers(ctx, applyEndpoints, connectOpts...)
@@ -249,6 +262,8 @@ func serve(args []string) error {
r.Handle("/v1/dep-tokens", apiAuthMiddleware(*flAPIKey, applyAPIHandlers.DEPTokensHandler)).Methods("PUT")
r.Handle("/v1/blueprints", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetBlueprintsHandler)).Methods("GET")
r.Handle("/v1/blueprints", apiAuthMiddleware(*flAPIKey, applyAPIHandlers.BlueprintHandler)).Methods("PUT")
r.Handle("/v1/profiles", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetProfilesHandler)).Methods("GET")
r.Handle("/v1/profiles", apiAuthMiddleware(*flAPIKey, applyAPIHandlers.ProfileHandler)).Methods("PUT")
}
if *flRepoPath != "" {