Switched Android from go-kit/log to slog (#39785)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #39785 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [ ] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. - Changes file already updated. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated internal logging infrastructure across Android MDM services and background jobs to use standard Go logging. * Enhanced test coverage for access control and permission enforcement across various endpoints and user roles. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
+3
-3
@@ -991,7 +991,7 @@ func newCleanupsAndAggregationSchedule(
|
||||
return ds.RenewMDMManagedCertificates(ctx)
|
||||
}),
|
||||
schedule.WithJob("renew_android_certificate_templates", func(ctx context.Context) error {
|
||||
return android_svc.RenewCertificateTemplates(ctx, ds, logger)
|
||||
return android_svc.RenewCertificateTemplates(ctx, ds, logger.SlogLogger())
|
||||
}),
|
||||
schedule.WithJob("query_results_cleanup", func(ctx context.Context) error {
|
||||
config, err := ds.AppConfig(ctx)
|
||||
@@ -1412,7 +1412,7 @@ func newAndroidMDMProfileManagerSchedule(
|
||||
ctx, name, instanceID, defaultInterval, ds, ds,
|
||||
schedule.WithLogger(logger),
|
||||
schedule.WithJob("manage_android_profiles", func(ctx context.Context) error {
|
||||
return android_svc.ReconcileProfiles(ctx, ds, logger, licenseKey, androidAgentConfig)
|
||||
return android_svc.ReconcileProfiles(ctx, ds, logger.SlogLogger(), licenseKey, androidAgentConfig)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -1848,7 +1848,7 @@ func newAndroidMDMDeviceReconcilerSchedule(
|
||||
ctx, name, instanceID, defaultInterval, ds, ds,
|
||||
schedule.WithLogger(logger),
|
||||
schedule.WithJob("reconcile_android_devices", func(ctx context.Context) error {
|
||||
return android_svc.ReconcileAndroidDevices(ctx, ds, logger, licenseKey)
|
||||
return android_svc.ReconcileAndroidDevices(ctx, ds, logger.SlogLogger(), licenseKey)
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -850,7 +850,7 @@ the way that the Fleet server works.
|
||||
config.MDM.AndroidAgent.Validate(initFatal)
|
||||
androidSvc, err := android_service.NewService(
|
||||
ctx,
|
||||
logger,
|
||||
logger.SlogLogger(),
|
||||
ds,
|
||||
config.License.Key,
|
||||
config.Server.PrivateKey,
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -16,8 +15,6 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android"
|
||||
"github.com/go-json-experiment/json"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/api/androidmanagement/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
@@ -27,7 +24,7 @@ import (
|
||||
// GoogleClient connects directly to Google's Android Management API. It is intended to be used for development/debugging.
|
||||
// To enable, set the following env vars: FLEET_DEV_ANDROID_GOOGLE_CLIENT=1 and FLEET_DEV_ANDROID_GOOGLE_SERVICE_CREDENTIALS=$(cat credentials.json)
|
||||
type GoogleClient struct {
|
||||
logger kitlog.Logger
|
||||
logger *slog.Logger
|
||||
mgmt *androidmanagement.Service
|
||||
androidServiceCredentials string
|
||||
androidProjectID string
|
||||
@@ -36,7 +33,7 @@ type GoogleClient struct {
|
||||
// Compile-time check to ensure that ProxyClient implements Client.
|
||||
var _ Client = &GoogleClient{}
|
||||
|
||||
func NewGoogleClient(ctx context.Context, logger kitlog.Logger, getenv dev_mode.GetEnv) Client {
|
||||
func NewGoogleClient(ctx context.Context, logger *slog.Logger, getenv dev_mode.GetEnv) Client {
|
||||
androidServiceCredentials := getenv("FLEET_DEV_ANDROID_GOOGLE_SERVICE_CREDENTIALS")
|
||||
if androidServiceCredentials == "" {
|
||||
return nil
|
||||
@@ -49,17 +46,16 @@ func NewGoogleClient(ctx context.Context, logger kitlog.Logger, getenv dev_mode.
|
||||
var creds credentials
|
||||
err := json.Unmarshal([]byte(androidServiceCredentials), &creds)
|
||||
if err != nil {
|
||||
level.Error(logger).Log("msg", "unmarshaling android service credentials", "err", err)
|
||||
logger.ErrorContext(ctx, "unmarshaling android service credentials", "err", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
slogLogger := slog.New(slog.NewTextHandler(os.Stdout, nil))
|
||||
mgmt, err := androidmanagement.NewService(ctx,
|
||||
option.WithCredentialsJSON([]byte(androidServiceCredentials)),
|
||||
option.WithLogger(slogLogger),
|
||||
option.WithLogger(logger),
|
||||
)
|
||||
if err != nil {
|
||||
level.Error(logger).Log("msg", "creating android management service", "err", err)
|
||||
logger.ErrorContext(ctx, "creating android management service", "err", err)
|
||||
return nil
|
||||
}
|
||||
return &GoogleClient{
|
||||
@@ -202,7 +198,7 @@ func (g *GoogleClient) EnterprisesPoliciesPatch(ctx context.Context, policyName
|
||||
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
g.logger.Log("msg", "Android policy not modified", "policy_name", policyName)
|
||||
g.logger.InfoContext(ctx, "Android policy not modified", "policy_name", policyName)
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, fmt.Errorf("patching policy %s: %w", policyName, err)
|
||||
@@ -214,7 +210,7 @@ func (g *GoogleClient) EnterprisesDevicesPatch(ctx context.Context, deviceName s
|
||||
ret, err := g.mgmt.Enterprises.Devices.Patch(deviceName, device).Context(ctx).Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
g.logger.Log("msg", "Android device not modified", "device_name", deviceName)
|
||||
g.logger.InfoContext(ctx, "Android device not modified", "device_name", deviceName)
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, fmt.Errorf("patching device %s: %w", deviceName, err)
|
||||
@@ -234,7 +230,7 @@ func (g *GoogleClient) EnterprisesDevicesDelete(ctx context.Context, deviceName
|
||||
_, err := g.mgmt.Enterprises.Devices.Delete(deviceName).Context(ctx).Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
g.logger.Log("msg", "Android device already deleted", "device_name", deviceName)
|
||||
g.logger.InfoContext(ctx, "Android device already deleted", "device_name", deviceName)
|
||||
return nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("deleting device %s: %w", deviceName, err)
|
||||
@@ -264,14 +260,14 @@ func (g *GoogleClient) EnterpriseDelete(ctx context.Context, enterpriseName stri
|
||||
// We can also pull the topic from the DB, but this way is more reliable.
|
||||
enterprise, err := g.mgmt.Enterprises.Get(enterpriseName).Context(ctx).Do()
|
||||
if err != nil {
|
||||
level.Error(g.logger).Log("msg", "getting enterprise; perhaps it was already deleted?", "err", err, "enterprise_name", enterpriseName)
|
||||
g.logger.ErrorContext(ctx, "getting enterprise; perhaps it was already deleted?", "err", err, "enterprise_name", enterpriseName)
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = g.mgmt.Enterprises.Delete(enterpriseName).Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
level.Info(g.logger).Log("msg", "enterprise was already deleted", "enterprise_name", enterpriseName)
|
||||
g.logger.InfoContext(ctx, "enterprise was already deleted", "enterprise_name", enterpriseName)
|
||||
return nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("deleting enterprise %s: %w", enterpriseName, err)
|
||||
@@ -284,7 +280,7 @@ func (g *GoogleClient) EnterpriseDelete(ctx context.Context, enterpriseName stri
|
||||
// PubSub topic and subscription have the same ID (but not name) by convention.
|
||||
topicAndSubscriptionID, err := getLastPart(ctx, enterprise.PubsubTopic)
|
||||
if err != nil || len(topicAndSubscriptionID) == 0 {
|
||||
level.Error(g.logger).Log("msg", "getting last part of PubSub topic", "err", err, "topic", enterprise.PubsubTopic)
|
||||
g.logger.ErrorContext(ctx, "getting last part of PubSub topic", "err", err, "topic", enterprise.PubsubTopic)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -370,7 +366,7 @@ func (g *GoogleClient) EnterprisesPoliciesModifyPolicyApplications(ctx context.C
|
||||
ret, err := g.mgmt.Enterprises.Policies.ModifyPolicyApplications(policyName, &req).Context(ctx).Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
g.logger.Log("msg", "Android application policy not modified", "policy_name", policyName)
|
||||
g.logger.InfoContext(ctx, "Android application policy not modified", "policy_name", policyName)
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, ctxerr.Wrapf(ctx, err, "modifying application policy %s", policyName)
|
||||
@@ -385,7 +381,7 @@ func (g *GoogleClient) EnterprisesPoliciesRemovePolicyApplications(ctx context.C
|
||||
ret, err := g.mgmt.Enterprises.Policies.RemovePolicyApplications(policyName, &req).Context(ctx).Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
g.logger.Log("msg", "Android application policy not modified", "policy_name", policyName)
|
||||
g.logger.InfoContext(ctx, "Android application policy not modified", "policy_name", policyName)
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, ctxerr.Wrapf(ctx, err, "removing packages from application policy %s", policyName)
|
||||
|
||||
@@ -16,8 +16,6 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/dev_mode"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android"
|
||||
"github.com/go-json-experiment/json"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"google.golang.org/api/androidmanagement/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/option"
|
||||
@@ -27,7 +25,7 @@ const defaultProxyEndpoint = "https://fleetdm.com/api/android/"
|
||||
|
||||
// ProxyClient connects to Google's Android Management API via a proxy, which is hosted at fleetdm.com by default.
|
||||
type ProxyClient struct {
|
||||
logger kitlog.Logger
|
||||
logger *slog.Logger
|
||||
mgmt *androidmanagement.Service
|
||||
licenseKey string
|
||||
proxyEndpoint string
|
||||
@@ -37,7 +35,7 @@ type ProxyClient struct {
|
||||
// Compile-time check to ensure that ProxyClient implements Client.
|
||||
var _ Client = &ProxyClient{}
|
||||
|
||||
func NewProxyClient(ctx context.Context, logger kitlog.Logger, licenseKey string, getenv dev_mode.GetEnv) Client {
|
||||
func NewProxyClient(ctx context.Context, logger *slog.Logger, licenseKey string, getenv dev_mode.GetEnv) Client {
|
||||
proxyEndpoint := getenv("FLEET_DEV_ANDROID_PROXY_ENDPOINT")
|
||||
if proxyEndpoint == "" {
|
||||
proxyEndpoint = defaultProxyEndpoint
|
||||
@@ -62,7 +60,7 @@ func NewProxyClient(ctx context.Context, logger kitlog.Logger, licenseKey string
|
||||
option.WithHTTPClient(fleethttp.NewClient()),
|
||||
)
|
||||
if err != nil {
|
||||
level.Error(logger).Log("msg", "creating android management service", "err", err)
|
||||
logger.ErrorContext(ctx, "creating android management service", "err", err)
|
||||
return nil
|
||||
}
|
||||
return &ProxyClient{
|
||||
@@ -180,7 +178,7 @@ func (p *ProxyClient) EnterprisesPoliciesPatch(ctx context.Context, policyName s
|
||||
ret, err := call.Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
p.logger.Log("msg", "Android policy not modified", "policy_name", policyName)
|
||||
p.logger.InfoContext(ctx, "Android policy not modified", "policy_name", policyName)
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, fmt.Errorf("patching policy %s: %w", policyName, err)
|
||||
@@ -194,7 +192,7 @@ func (p *ProxyClient) EnterprisesDevicesPatch(ctx context.Context, deviceName st
|
||||
ret, err := call.Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
p.logger.Log("msg", "Android device not modified", "device_name", deviceName)
|
||||
p.logger.InfoContext(ctx, "Android device not modified", "device_name", deviceName)
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, fmt.Errorf("patching device %s: %w", deviceName, err)
|
||||
@@ -218,7 +216,7 @@ func (p *ProxyClient) EnterprisesDevicesDelete(ctx context.Context, deviceName s
|
||||
_, err := call.Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err) || isErrorCode(err, http.StatusNotFound):
|
||||
p.logger.Log("msg", "Android device already deleted", "device_name", deviceName)
|
||||
p.logger.InfoContext(ctx, "Android device already deleted", "device_name", deviceName)
|
||||
return nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("deleting device %s: %w", deviceName, err)
|
||||
@@ -254,7 +252,7 @@ func (p *ProxyClient) EnterpriseDelete(ctx context.Context, enterpriseName strin
|
||||
_, err := call.Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err) || isErrorCode(err, http.StatusNotFound):
|
||||
level.Info(p.logger).Log("msg", "enterprise was already deleted", "enterprise_name", enterpriseName)
|
||||
p.logger.InfoContext(ctx, "enterprise was already deleted", "enterprise_name", enterpriseName)
|
||||
return nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("deleting enterprise %s: %w", enterpriseName, err)
|
||||
@@ -334,7 +332,7 @@ func (p *ProxyClient) EnterprisesPoliciesModifyPolicyApplications(ctx context.Co
|
||||
ret, err := call.Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
p.logger.Log("msg", "Android application policy not modified", "policy_name", policyName)
|
||||
p.logger.InfoContext(ctx, "Android application policy not modified", "policy_name", policyName)
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, ctxerr.Wrapf(ctx, err, "modifying application policy %s", policyName)
|
||||
@@ -352,7 +350,7 @@ func (p *ProxyClient) EnterprisesPoliciesRemovePolicyApplications(ctx context.Co
|
||||
ret, err := call.Do()
|
||||
switch {
|
||||
case googleapi.IsNotModified(err):
|
||||
p.logger.Log("msg", "Android application policy not modified", "policy_name", policyName)
|
||||
p.logger.InfoContext(ctx, "Android application policy not modified", "policy_name", policyName)
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, ctxerr.Wrapf(ctx, err, "removing packages from application policy %s", policyName)
|
||||
|
||||
@@ -2,16 +2,15 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
)
|
||||
|
||||
// RenewCertificateTemplates identifies Android certificate templates that are approaching
|
||||
// expiration and marks them for renewal by updating their status.
|
||||
func RenewCertificateTemplates(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger) error {
|
||||
func RenewCertificateTemplates(ctx context.Context, ds fleet.Datastore, logger *slog.Logger) error {
|
||||
const batchSize = 1000
|
||||
templates, err := ds.GetAndroidCertificateTemplatesForRenewal(ctx, batchSize)
|
||||
if err != nil {
|
||||
@@ -23,6 +22,6 @@ func RenewCertificateTemplates(ctx context.Context, ds fleet.Datastore, logger k
|
||||
if err := ds.SetAndroidCertificateTemplatesForRenewal(ctx, templates); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "set android certificate templates for renewal")
|
||||
}
|
||||
level.Info(logger).Log("msg", "marked android certificate templates for renewal", "count", len(templates))
|
||||
logger.InfoContext(ctx, "marked android certificate templates for renewal", "count", len(templates))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android"
|
||||
android_mock "github.com/fleetdm/fleet/v4/server/mdm/android/mock"
|
||||
ds_mock "github.com/fleetdm/fleet/v4/server/mock"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/service/modules/activities"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -28,10 +28,10 @@ import (
|
||||
func TestEnterprisesAuth(t *testing.T) {
|
||||
androidAPIClient := android_mock.Client{}
|
||||
androidAPIClient.InitCommonMocks()
|
||||
logger := kitlog.NewLogfmtLogger(os.Stdout)
|
||||
logger := logging.NewLogfmtLogger(os.Stdout)
|
||||
fleetDS := InitCommonDSMocks()
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
@@ -126,11 +126,11 @@ func TestEnterprisesAuth(t *testing.T) {
|
||||
func TestEnterpriseSignupMissingPrivateKey(t *testing.T) {
|
||||
androidAPIClient := android_mock.Client{}
|
||||
androidAPIClient.InitCommonMocks()
|
||||
logger := kitlog.NewLogfmtLogger(os.Stdout)
|
||||
logger := logging.NewLogfmtLogger(os.Stdout)
|
||||
fleetDS := InitCommonDSMocks()
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
user := &fleet.User{ID: 1, GlobalRole: ptr.String(fleet.RoleAdmin)}
|
||||
@@ -237,7 +237,7 @@ func (e *notFoundError) Error() string { return "not found" }
|
||||
func (e *notFoundError) IsNotFound() bool { return true }
|
||||
|
||||
func TestGetEnterprise(t *testing.T) {
|
||||
logger := kitlog.NewLogfmtLogger(os.Stdout)
|
||||
logger := logging.NewLogfmtLogger(os.Stdout)
|
||||
user := &fleet.User{ID: 1, GlobalRole: ptr.String(fleet.RoleAdmin)}
|
||||
ctx := viewer.NewContext(context.Background(), viewer.Viewer{User: user})
|
||||
|
||||
@@ -247,7 +247,7 @@ func TestGetEnterprise(t *testing.T) {
|
||||
|
||||
fleetDS := InitCommonDSMocks()
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
enterprise, err := svc.GetEnterprise(ctx)
|
||||
@@ -267,7 +267,7 @@ func TestGetEnterprise(t *testing.T) {
|
||||
}
|
||||
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
enterprise, err := svc.GetEnterprise(ctx)
|
||||
@@ -281,7 +281,7 @@ func TestGetEnterprise(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
|
||||
logger := kitlog.NewLogfmtLogger(os.Stdout)
|
||||
logger := logging.NewLogfmtLogger(os.Stdout)
|
||||
user := &fleet.User{ID: 1, GlobalRole: ptr.String(fleet.RoleAdmin)}
|
||||
ctx := viewer.NewContext(context.Background(), viewer.Viewer{User: user})
|
||||
|
||||
@@ -313,7 +313,7 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
|
||||
}
|
||||
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = svc.VerifyExistingEnterpriseIfAny(ctx)
|
||||
@@ -362,7 +362,7 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
|
||||
}
|
||||
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = svc.VerifyExistingEnterpriseIfAny(ctx)
|
||||
@@ -403,7 +403,7 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
|
||||
}
|
||||
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = svc.VerifyExistingEnterpriseIfAny(ctx)
|
||||
@@ -444,7 +444,7 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
|
||||
}
|
||||
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = svc.VerifyExistingEnterpriseIfAny(ctx)
|
||||
@@ -511,7 +511,7 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
|
||||
}
|
||||
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = svc.VerifyExistingEnterpriseIfAny(ctx)
|
||||
@@ -541,7 +541,7 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
|
||||
}
|
||||
|
||||
activityModule := activities.NewActivityModule(fleetDS, logger)
|
||||
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
svc, err := NewServiceWithClient(logger.SlogLogger(), fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = svc.VerifyExistingEnterpriseIfAny(ctx)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"net/http"
|
||||
"slices"
|
||||
@@ -15,17 +16,16 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android/service/androidmgmt"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"google.golang.org/api/androidmanagement/v1"
|
||||
)
|
||||
|
||||
func ReconcileProfiles(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger, licenseKey string, androidAgentConfig config.AndroidAgentConfig) error {
|
||||
func ReconcileProfiles(ctx context.Context, ds fleet.Datastore, logger *slog.Logger, licenseKey string, androidAgentConfig config.AndroidAgentConfig) error {
|
||||
return ReconcileProfilesWithClient(ctx, ds, logger, licenseKey, nil, androidAgentConfig)
|
||||
}
|
||||
|
||||
// ReconcileProfilesWithClient is like ReconcileProfiles but allows injecting a custom client for testing.
|
||||
// If client is nil, a new AMAPI client will be created.
|
||||
func ReconcileProfilesWithClient(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger, licenseKey string, client androidmgmt.Client, androidAgentConfig config.AndroidAgentConfig) error {
|
||||
func ReconcileProfilesWithClient(ctx context.Context, ds fleet.Datastore, logger *slog.Logger, licenseKey string, client androidmgmt.Client, androidAgentConfig config.AndroidAgentConfig) error {
|
||||
appConfig, err := ds.AppConfig(ctx)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "get app config")
|
||||
@@ -71,7 +71,7 @@ type profileReconciler struct {
|
||||
Enterprise *android.Enterprise
|
||||
Client androidmgmt.Client
|
||||
AndroidAgentConfig config.AndroidAgentConfig
|
||||
Logger kitlog.Logger
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func getClientAuthenticationSecret(ctx context.Context, ds fleet.Datastore) (string, error) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -16,9 +17,9 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android/mock"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android/service/androidmgmt"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/test"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -100,7 +101,7 @@ func TestReconcileProfiles(t *testing.T) {
|
||||
Package: "com.fleetdm.agent",
|
||||
SigningSHA256: "abc123def456",
|
||||
},
|
||||
Logger: kitlog.NewNopLogger(),
|
||||
Logger: slog.New(logging.DiscardHandler{}),
|
||||
}
|
||||
|
||||
c.fn(t, ds, client, reconciler)
|
||||
@@ -1007,7 +1008,7 @@ func testBuildAndSendFleetAgentConfigForEnrollment(t *testing.T, ds fleet.Datast
|
||||
// Create service and call BuildAndSendFleetAgentConfig with skipHostsWithoutNewCerts=false
|
||||
// This simulates the enrollment flow from software_worker.go
|
||||
svc := &Service{
|
||||
logger: kitlog.NewNopLogger(),
|
||||
logger: slog.New(logging.DiscardHandler{}),
|
||||
fleetDS: ds,
|
||||
ds: ds.(fleet.AndroidDatastore),
|
||||
androidAPIClient: client,
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/worker"
|
||||
"github.com/go-json-experiment/json"
|
||||
"github.com/go-kit/log/level"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
"google.golang.org/api/androidmanagement/v1"
|
||||
@@ -45,7 +44,7 @@ func (svc *Service) ProcessPubSubPush(ctx context.Context, token string, message
|
||||
svc.authz.SkipAuthorization(ctx)
|
||||
return nil
|
||||
}
|
||||
level.Debug(svc.logger).Log("msg", "Received PubSub message", "notification", notificationType)
|
||||
svc.logger.DebugContext(ctx, "Received PubSub message", "notification", notificationType)
|
||||
if android.NotificationType(notificationType) == android.PubSubTest {
|
||||
// Nothing to process
|
||||
svc.authz.SkipAuthorization(ctx)
|
||||
@@ -69,7 +68,7 @@ func (svc *Service) ProcessPubSubPush(ctx context.Context, token string, message
|
||||
return svc.handlePubSubStatusReport(ctx, token, rawData)
|
||||
default:
|
||||
// Ignore unknown notification types
|
||||
level.Debug(svc.logger).Log("msg", "Ignoring PubSub notification type", "notification", notificationType)
|
||||
svc.logger.DebugContext(ctx, "Ignoring PubSub notification type", "notification", notificationType)
|
||||
svc.authz.SkipAuthorization(ctx)
|
||||
return nil
|
||||
}
|
||||
@@ -151,7 +150,7 @@ func (svc *Service) handlePubSubStatusReport(ctx context.Context, token string,
|
||||
}
|
||||
|
||||
if isDeleted {
|
||||
level.Debug(svc.logger).Log("msg", "Android device deleted from MDM", "device.name", device.Name,
|
||||
svc.logger.DebugContext(ctx, "Android device deleted from MDM", "device.name", device.Name,
|
||||
"device.enterpriseSpecificId", device.HardwareInfo.EnterpriseSpecificId)
|
||||
|
||||
// User-initiated unenroll (work profile removed) or device deleted via AMAPI.
|
||||
@@ -203,18 +202,18 @@ func (svc *Service) handlePubSubStatusReport(ctx context.Context, token string,
|
||||
return ctxerr.Wrap(ctx, err, "getting existing Android host")
|
||||
}
|
||||
if host == nil {
|
||||
level.Debug(svc.logger).Log("msg", "Device not found in Fleet. Perhaps it was deleted, "+
|
||||
svc.logger.DebugContext(ctx, "Device not found in Fleet. Perhaps it was deleted, "+
|
||||
"but it is still connected via Android MDM. Re-enrolling", "device.name", device.Name,
|
||||
"device.enterpriseSpecificId", device.HardwareInfo.EnterpriseSpecificId)
|
||||
err = svc.enrollHost(ctx, &device)
|
||||
if err != nil {
|
||||
level.Debug(svc.logger).Log("msg", "Error re-enrolling Android host", "data", rawData)
|
||||
svc.logger.DebugContext(ctx, "Error re-enrolling Android host", "data", rawData)
|
||||
return ctxerr.Wrap(ctx, err, "re-enrolling deleted Android host")
|
||||
}
|
||||
}
|
||||
err = svc.updateHost(ctx, &device, host, false)
|
||||
if err != nil {
|
||||
level.Debug(svc.logger).Log("msg", "Error updating Android host", "data", rawData)
|
||||
svc.logger.DebugContext(ctx, "Error updating Android host", "data", rawData)
|
||||
return ctxerr.Wrap(ctx, err, "enrolling Android host")
|
||||
}
|
||||
err = svc.updateHostSoftware(ctx, &device, host)
|
||||
@@ -327,7 +326,7 @@ func (svc *Service) handlePubSubEnrollment(ctx context.Context, token string, ra
|
||||
|
||||
err = svc.enrollHost(ctx, &device)
|
||||
if err != nil {
|
||||
level.Debug(svc.logger).Log("msg", "Error enrolling Android host", "data", rawData)
|
||||
svc.logger.DebugContext(ctx, "Error enrolling Android host", "data", rawData)
|
||||
return ctxerr.Wrap(ctx, err, "enrolling Android host")
|
||||
}
|
||||
return nil
|
||||
@@ -360,7 +359,7 @@ func (svc *Service) enrollHost(ctx context.Context, device *androidmanagement.De
|
||||
}
|
||||
|
||||
if host != nil {
|
||||
level.Debug(svc.logger).Log("msg", "The enrolling Android host is already present in Fleet. Updating team if needed",
|
||||
svc.logger.DebugContext(ctx, "The enrolling Android host is already present in Fleet. Updating team if needed",
|
||||
"device.name", device.Name, "device.enterpriseSpecificId", device.HardwareInfo.EnterpriseSpecificId)
|
||||
enrollSecret, err := svc.ds.VerifyEnrollSecret(ctx, enrollmentTokenRequest.EnrollSecret)
|
||||
if err != nil && !fleet.IsNotFound(err) {
|
||||
@@ -466,7 +465,7 @@ func (svc *Service) updateHost(ctx context.Context, device *androidmanagement.De
|
||||
teamID = *host.Host.TeamID
|
||||
}
|
||||
if _, err := svc.fleetDS.CreatePendingCertificateTemplatesForNewHost(ctx, host.Host.UUID, teamID); err != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to create pending certificate templates for re-enrolled host", "host_uuid", host.Host.UUID, "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to create pending certificate templates for re-enrolled host", "host_uuid", host.Host.UUID, "err", err)
|
||||
return ctxerr.Wrap(ctx, err, "creating pending certificate templates for re-enrolled host")
|
||||
}
|
||||
|
||||
@@ -574,7 +573,7 @@ func (svc *Service) addNewHost(ctx context.Context, device *androidmanagement.De
|
||||
}
|
||||
|
||||
if enrollmentTokenRequest.IdpUUID != "" {
|
||||
level.Info(svc.logger).Log("msg", "associating android host with idp account", "host_uuid", host.UUID, "idp_uuid", enrollmentTokenRequest.IdpUUID)
|
||||
svc.logger.InfoContext(ctx, "associating android host with idp account", "host_uuid", host.UUID, "idp_uuid", enrollmentTokenRequest.IdpUUID)
|
||||
err := svc.ds.AssociateHostMDMIdPAccount(ctx, host.UUID, enrollmentTokenRequest.IdpUUID)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "associating host with idp account")
|
||||
@@ -591,7 +590,7 @@ func (svc *Service) addNewHost(ctx context.Context, device *androidmanagement.De
|
||||
teamID = *enrollSecret.GetTeamID()
|
||||
}
|
||||
if _, err := svc.fleetDS.CreatePendingCertificateTemplatesForNewHost(ctx, fleetHost.Host.UUID, teamID); err != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to create pending certificate templates for new host", "host_uuid", fleetHost.Host.UUID, "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to create pending certificate templates for new host", "host_uuid", fleetHost.Host.UUID, "err", err)
|
||||
return ctxerr.Wrap(ctx, err, "creating pending certificate templates for new host")
|
||||
}
|
||||
|
||||
@@ -640,7 +639,7 @@ func (svc *Service) getPolicyID(ctx context.Context, device *androidmanagement.D
|
||||
return nil, ctxerr.Errorf(ctx, "invalid Android policy name: %s", device.AppliedPolicyName)
|
||||
}
|
||||
if len(nameParts[3]) == 0 {
|
||||
level.Error(svc.logger).Log("msg", "Empty Android policy ID", "device.name", device.Name,
|
||||
svc.logger.ErrorContext(ctx, "Empty Android policy ID", "device.name", device.Name,
|
||||
"device.enterpriseSpecificID", device.HardwareInfo.EnterpriseSpecificId, "device.AppliedPolicyName",
|
||||
device.AppliedPolicyName)
|
||||
return nil, nil
|
||||
@@ -651,7 +650,7 @@ func (svc *Service) getPolicyID(ctx context.Context, device *androidmanagement.D
|
||||
func (svc *Service) verifyDevicePolicy(ctx context.Context, hostUUID string, device *androidmanagement.Device) {
|
||||
appliedPolicyVersion := device.AppliedPolicyVersion
|
||||
|
||||
level.Debug(svc.logger).Log("msg", "Verifying Android device policy", "host_uuid", hostUUID, "applied_policy_version", appliedPolicyVersion)
|
||||
svc.logger.DebugContext(ctx, "Verifying Android device policy", "host_uuid", hostUUID, "applied_policy_version", appliedPolicyVersion)
|
||||
|
||||
// Get all host_mdm_android_profiles that are pending or failed due to non compliance reasons,
|
||||
// and included_in_policy_version <= device.AppliedPolicyVersion. That way we can either fully
|
||||
@@ -660,7 +659,7 @@ func (svc *Service) verifyDevicePolicy(ctx context.Context, hostUUID string, dev
|
||||
// Get all profiles that are pending or failed install
|
||||
pendingInstallProfiles, err := svc.ds.ListHostMDMAndroidProfilesPendingOrFailedInstallWithVersion(ctx, hostUUID, appliedPolicyVersion)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error getting pending profiles", "err", err)
|
||||
svc.logger.ErrorContext(ctx, "error getting pending profiles", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -684,7 +683,7 @@ func (svc *Service) verifyDevicePolicy(ctx context.Context, hostUUID string, dev
|
||||
|
||||
err = svc.ds.BulkUpsertMDMAndroidHostProfiles(ctx, verifiedProfiles)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error verifying pending install profiles", "err", err)
|
||||
svc.logger.ErrorContext(ctx, "error verifying pending install profiles", "err", err)
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -700,19 +699,19 @@ func (svc *Service) verifyDevicePolicy(ctx context.Context, hostUUID string, dev
|
||||
// Then re-use the map above, so we can iterate over it again, but now the payload is already unmarshalled.
|
||||
policyRequest, err := svc.ds.GetAndroidPolicyRequestByUUID(ctx, policyRequestUUID)
|
||||
if err != nil && !fleet.IsNotFound(err) {
|
||||
level.Error(svc.logger).Log("msg", "error getting policy request", "err", err, "policy_request_uuid", policyRequestUUID, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "error getting policy request", "err", err, "policy_request_uuid", policyRequestUUID, "host_uuid", hostUUID)
|
||||
return
|
||||
}
|
||||
|
||||
if fleet.IsNotFound(err) {
|
||||
level.Error(svc.logger).Log("msg", "policy request not found", "policy_request_uuid", policyRequestUUID, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "policy request not found", "policy_request_uuid", policyRequestUUID, "host_uuid", hostUUID)
|
||||
return
|
||||
}
|
||||
|
||||
var policyRequestPayload fleet.AndroidPolicyRequestPayload
|
||||
err = json.Unmarshal(policyRequest.Payload, &policyRequestPayload)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error unmarshalling policy request payload", "err", err, "policy_request_uuid", policyRequestUUID, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "error unmarshalling policy request payload", "err", err, "policy_request_uuid", policyRequestUUID, "host_uuid", hostUUID)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -758,7 +757,7 @@ func (svc *Service) verifyDevicePolicy(ctx context.Context, hostUUID string, dev
|
||||
|
||||
err = svc.ds.BulkUpsertMDMAndroidHostProfiles(ctx, profiles)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error upserting android profiles", "err", err, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "error upserting android profiles", "err", err, "host_uuid", hostUUID)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -766,7 +765,7 @@ func (svc *Service) verifyDevicePolicy(ctx context.Context, hostUUID string, dev
|
||||
// Bulk delete any pending or failed remove profiles.
|
||||
err = svc.ds.BulkDeleteMDMAndroidHostProfiles(ctx, hostUUID, appliedPolicyVersion)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error deleting pending or failed remove profiles", "err", err, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "error deleting pending or failed remove profiles", "err", err, "host_uuid", hostUUID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,14 +773,14 @@ func (svc *Service) verifyDeviceSoftware(ctx context.Context, host *fleet.Host,
|
||||
appliedPolicyVersion := device.AppliedPolicyVersion
|
||||
hostUUID := host.UUID
|
||||
|
||||
level.Debug(svc.logger).Log("msg", "Verifying Android device software", "host_uuid", hostUUID, "applied_policy_version", appliedPolicyVersion)
|
||||
svc.logger.DebugContext(ctx, "Verifying Android device software", "host_uuid", hostUUID, "applied_policy_version", appliedPolicyVersion)
|
||||
|
||||
// Get all host_vpp_software_installs that are pending, and set in a policy version <= device.AppliedPolicyVersion.
|
||||
// That way we can either fully verify the app install, or mark as failed if the app is not compliant.
|
||||
|
||||
pendingInstallApps, err := svc.ds.ListHostMDMAndroidVPPAppsPendingInstallWithVersion(ctx, hostUUID, appliedPolicyVersion)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error getting pending vpp installs", "err", err)
|
||||
svc.logger.ErrorContext(ctx, "error getting pending vpp installs", "err", err)
|
||||
return
|
||||
}
|
||||
if len(pendingInstallApps) == 0 {
|
||||
@@ -820,11 +819,11 @@ func (svc *Service) verifyDeviceSoftware(ctx context.Context, host *fleet.Host,
|
||||
if appReport.State == "INSTALLED" {
|
||||
// definitely installed successfully
|
||||
markVerified[appReport.PackageName] = true
|
||||
level.Debug(svc.logger).Log("msg", "Software marked as verified", "host_uuid", hostUUID, "package_name", appReport.PackageName)
|
||||
svc.logger.DebugContext(ctx, "Software marked as verified", "host_uuid", hostUUID, "package_name", appReport.PackageName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
level.Debug(svc.logger).Log("msg", "Software not marked as verified, checking if failed", "host_uuid", hostUUID, "package_name", appReport.PackageName)
|
||||
svc.logger.DebugContext(ctx, "Software not marked as verified, checking if failed", "host_uuid", hostUUID, "package_name", appReport.PackageName)
|
||||
}
|
||||
|
||||
// for the remaining apps, mark as failed if non-conformant
|
||||
@@ -838,7 +837,7 @@ func (svc *Service) verifyDeviceSoftware(ctx context.Context, host *fleet.Host,
|
||||
if report.NonComplianceReason == "PENDING" || report.InstallationFailureReason == "IN_PROGRESS" {
|
||||
// keep as pending, the understanding is that another pub-sub will follow when the app's state
|
||||
// chances to installed or failed.
|
||||
level.Debug(svc.logger).Log("msg", "Software not reported as installed yet, will remain pending", "host_uuid", hostUUID, "package_name", packageName,
|
||||
svc.logger.DebugContext(ctx, "Software not reported as installed yet, will remain pending", "host_uuid", hostUUID, "package_name", packageName,
|
||||
"non_compliance_reason", report.NonComplianceReason,
|
||||
"installation_failure_reason", report.InstallationFailureReason)
|
||||
continue
|
||||
@@ -846,7 +845,7 @@ func (svc *Service) verifyDeviceSoftware(ctx context.Context, host *fleet.Host,
|
||||
|
||||
// otherwise it has failed to install, mark as failed
|
||||
markVerified[packageName] = false
|
||||
level.Error(svc.logger).Log("msg", "Software failed to install", "host_uuid", hostUUID, "package_name", packageName,
|
||||
svc.logger.ErrorContext(ctx, "Software failed to install", "host_uuid", hostUUID, "package_name", packageName,
|
||||
"non_compliance_reason", report.NonComplianceReason,
|
||||
"installation_failure_reason", report.InstallationFailureReason,
|
||||
"specific_non_compliance_reason", report.SpecificNonComplianceReason)
|
||||
@@ -858,7 +857,7 @@ func (svc *Service) verifyDeviceSoftware(ctx context.Context, host *fleet.Host,
|
||||
// failed, we don't know how long it might take for the device to receive another
|
||||
// policy, it may never happen.
|
||||
markVerified[packageName] = false
|
||||
level.Error(svc.logger).Log("msg", "Software failed to install without non-compliance report", "host_uuid", hostUUID, "package_name", packageName,
|
||||
svc.logger.ErrorContext(ctx, "Software failed to install without non-compliance report", "host_uuid", hostUUID, "package_name", packageName,
|
||||
"installation_failure_reason", "unknown - no non-compliance report received")
|
||||
}
|
||||
|
||||
@@ -875,11 +874,11 @@ func (svc *Service) verifyDeviceSoftware(ctx context.Context, host *fleet.Host,
|
||||
}
|
||||
}
|
||||
if err := svc.ds.BulkSetVPPInstallsAsVerified(ctx, host.ID, toVerifyUUIDs); err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error marking vpp installs as verified", "err", err, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "error marking vpp installs as verified", "err", err, "host_uuid", hostUUID)
|
||||
return
|
||||
}
|
||||
if err := svc.ds.BulkSetVPPInstallsAsFailed(ctx, host.ID, toFailUUIDs); err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error marking vpp installs as failed", "err", err, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "error marking vpp installs as failed", "err", err, "host_uuid", hostUUID)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -891,17 +890,17 @@ func (svc *Service) verifyDeviceSoftware(ctx context.Context, host *fleet.Host,
|
||||
return false
|
||||
}
|
||||
// otherwise it's a DB error and we should fail
|
||||
level.Error(svc.logger).Log("msg", "error getting past activity for installed software", "err", err, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "error getting past activity for installed software", "err", err, "host_uuid", hostUUID)
|
||||
return true
|
||||
}
|
||||
if act == nil {
|
||||
// could happen if command is not found, but shouldn't
|
||||
level.Debug(svc.logger).Log("msg", "getting past activity for installed software did not find the command", "host_uuid", hostUUID)
|
||||
svc.logger.DebugContext(ctx, "getting past activity for installed software did not find the command", "host_uuid", hostUUID)
|
||||
return false
|
||||
}
|
||||
act.FromSetupExperience = true // currently, all Android app installs are from setup experience
|
||||
if err := svc.activityModule.NewActivity(ctx, user, act); err != nil {
|
||||
level.Error(svc.logger).Log("msg", "error creating past activity for installed software", "err", err, "host_uuid", hostUUID)
|
||||
svc.logger.ErrorContext(ctx, "error creating past activity for installed software", "err", err, "host_uuid", hostUUID)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -969,8 +968,7 @@ func (svc *Service) calculateAndroidStorageMetrics(
|
||||
}
|
||||
|
||||
// Log memory events for debugging
|
||||
level.Debug(svc.logger).Log(
|
||||
"msg", logPrefix+logSuffix,
|
||||
svc.logger.DebugContext(ctx, logPrefix+logSuffix,
|
||||
"device_id", device.HardwareInfo.EnterpriseSpecificId,
|
||||
"total_internal_storage", totalStorageBytes,
|
||||
"memory_events_count", len(device.MemoryEvents),
|
||||
@@ -990,8 +988,7 @@ func (svc *Service) calculateAndroidStorageMetrics(
|
||||
var latestExternalMeasuredTime time.Time
|
||||
|
||||
for _, event := range device.MemoryEvents {
|
||||
level.Debug(svc.logger).Log(
|
||||
"msg", "Android memory event"+logSuffix,
|
||||
svc.logger.DebugContext(ctx, "Android memory event"+logSuffix,
|
||||
"event_type", event.EventType,
|
||||
"byte_count", event.ByteCount,
|
||||
"create_time", event.CreateTime,
|
||||
@@ -1000,8 +997,7 @@ func (svc *Service) calculateAndroidStorageMetrics(
|
||||
eventTime, err := time.Parse(time.RFC3339, event.CreateTime)
|
||||
if err != nil {
|
||||
// Log parse error but continue processing
|
||||
level.Debug(svc.logger).Log(
|
||||
"msg", "Failed to parse event time"+logSuffix,
|
||||
svc.logger.DebugContext(ctx, "Failed to parse event time"+logSuffix,
|
||||
"event_type", event.EventType,
|
||||
"create_time", event.CreateTime,
|
||||
"error", err,
|
||||
@@ -1051,8 +1047,7 @@ func (svc *Service) calculateAndroidStorageMetrics(
|
||||
gigsDiskSpaceAvailable = -1
|
||||
percentDiskSpaceAvailable = -1
|
||||
|
||||
level.Debug(svc.logger).Log(
|
||||
"msg", "Android storage measurement not supported"+logSuffix,
|
||||
svc.logger.DebugContext(ctx, "Android storage measurement not supported"+logSuffix,
|
||||
"device_id", device.HardwareInfo.EnterpriseSpecificId,
|
||||
"total_storage_bytes", totalStorageBytes,
|
||||
"reason", "Only DETECTED events, no MEASURED events",
|
||||
@@ -1061,8 +1056,7 @@ func (svc *Service) calculateAndroidStorageMetrics(
|
||||
gigsDiskSpaceAvailable = float64(totalAvailableBytes) / (1024 * 1024 * 1024)
|
||||
percentDiskSpaceAvailable = (float64(totalAvailableBytes) / float64(totalStorageBytes)) * 100
|
||||
|
||||
level.Debug(svc.logger).Log(
|
||||
"msg", "Android storage calculation complete"+logSuffix,
|
||||
svc.logger.DebugContext(ctx, "Android storage calculation complete"+logSuffix,
|
||||
"total_storage_bytes", totalStorageBytes,
|
||||
"total_available_bytes", totalAvailableBytes,
|
||||
"gigs_total", gigsTotalDiskSpace,
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -16,10 +17,10 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android"
|
||||
android_mock "github.com/fleetdm/fleet/v4/server/mdm/android/mock"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/logging"
|
||||
common_mysql "github.com/fleetdm/fleet/v4/server/platform/mysql"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/service/modules/activities"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/api/androidmanagement/v1"
|
||||
@@ -31,9 +32,9 @@ const testBrandTestSerialHashed = "9c311e05af14f958bd65188796e41fcc8a7b0ff913bfe
|
||||
func createAndroidService(t *testing.T) (android.Service, *AndroidMockDS) {
|
||||
androidAPIClient := android_mock.Client{}
|
||||
androidAPIClient.InitCommonMocks()
|
||||
logger := kitlog.NewLogfmtLogger(os.Stdout)
|
||||
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
|
||||
mockDS := InitCommonDSMocks()
|
||||
activityModule := activities.NewActivityModule(mockDS, logger)
|
||||
activityModule := activities.NewActivityModule(mockDS, logging.NewLogger(logger))
|
||||
svc, err := NewServiceWithClient(logger, mockDS, &androidAPIClient, "test-private-key", &mockDS.DataStore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -3,18 +3,17 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
)
|
||||
|
||||
// ReconcileAndroidDevices polls AMAPI for devices that Fleet still considers enrolled
|
||||
// and flips them to unenrolled if Google reports them missing (404).
|
||||
// This complements (does not replace) Pub/Sub DELETED handling.
|
||||
func ReconcileAndroidDevices(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger, licenseKey string) error {
|
||||
func ReconcileAndroidDevices(ctx context.Context, ds fleet.Datastore, logger *slog.Logger, licenseKey string) error {
|
||||
appConfig, err := ds.AppConfig(ctx)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "get app config")
|
||||
@@ -80,7 +79,7 @@ func ReconcileAndroidDevices(ctx context.Context, ds fleet.Datastore, logger kit
|
||||
continue
|
||||
case !ok:
|
||||
if _, derr := ds.SetAndroidHostUnenrolled(ctx, dev.HostID); derr != nil {
|
||||
level.Error(logger).Log("msg", "failed to mark android host unenrolled during reconcile", "host_id", dev.HostID, "err", derr)
|
||||
logger.ErrorContext(ctx, "failed to mark android host unenrolled during reconcile", "host_id", dev.HostID, "err", derr)
|
||||
continue
|
||||
}
|
||||
// Emit system activity to mirror Pub/Sub DELETED handling.
|
||||
@@ -95,13 +94,13 @@ func ReconcileAndroidDevices(ctx context.Context, ds fleet.Datastore, logger kit
|
||||
InstalledFromDEP: false,
|
||||
Platform: "android",
|
||||
}, nil, time.Now()); aerr != nil {
|
||||
level.Debug(logger).Log("msg", "failed to create mdm_unenrolled activity during android reconcile", "host_id", dev.HostID, "err", aerr)
|
||||
logger.DebugContext(ctx, "failed to create mdm_unenrolled activity during android reconcile", "host_id", dev.HostID, "err", aerr)
|
||||
}
|
||||
unenrolled++
|
||||
level.Debug(logger).Log("msg", "android device missing in Google; marked unenrolled", "host_id", dev.HostID, "device", deviceName)
|
||||
logger.DebugContext(ctx, "android device missing in Google; marked unenrolled", "host_id", dev.HostID, "device", deviceName)
|
||||
}
|
||||
}
|
||||
|
||||
level.Debug(logger).Log("msg", "android reconcile complete", "checked", checked, "unenrolled", unenrolled)
|
||||
logger.DebugContext(ctx, "android reconcile complete", "checked", checked, "unenrolled", unenrolled)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -23,8 +24,6 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android/service/androidmgmt"
|
||||
"github.com/fleetdm/fleet/v4/server/service/modules/activities"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"google.golang.org/api/androidmanagement/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
@@ -38,7 +37,7 @@ const (
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
logger kitlog.Logger
|
||||
logger *slog.Logger
|
||||
authz *authz.Authorizer
|
||||
ds fleet.AndroidDatastore
|
||||
fleetDS fleet.Datastore
|
||||
@@ -57,7 +56,7 @@ type Service struct {
|
||||
|
||||
func NewService(
|
||||
ctx context.Context,
|
||||
logger kitlog.Logger,
|
||||
logger *slog.Logger,
|
||||
ds fleet.AndroidDatastore,
|
||||
licenseKey string,
|
||||
serverPrivateKey string,
|
||||
@@ -70,7 +69,7 @@ func NewService(
|
||||
}
|
||||
|
||||
func NewServiceWithClient(
|
||||
logger kitlog.Logger,
|
||||
logger *slog.Logger,
|
||||
ds fleet.AndroidDatastore,
|
||||
client androidmgmt.Client,
|
||||
serverPrivateKey string,
|
||||
@@ -108,7 +107,7 @@ func NewServiceWithClient(
|
||||
return svc, nil
|
||||
}
|
||||
|
||||
func newAMAPIClient(ctx context.Context, logger kitlog.Logger, licenseKey string) androidmgmt.Client {
|
||||
func newAMAPIClient(ctx context.Context, logger *slog.Logger, licenseKey string) androidmgmt.Client {
|
||||
var client androidmgmt.Client
|
||||
getEnv := dev_mode.Env
|
||||
if getEnv("FLEET_DEV_ANDROID_GOOGLE_CLIENT") == "1" || strings.ToUpper(getEnv("FLEET_DEV_ANDROID_GOOGLE_CLIENT")) == "ON" {
|
||||
@@ -372,7 +371,7 @@ func (svc *Service) EnterpriseSignupCallback(ctx context.Context, signupToken st
|
||||
switch {
|
||||
case fleet.IsNotFound(err):
|
||||
// This should never happen.
|
||||
level.Error(svc.logger).Log("msg", "User that created the Android enterprise was not found", "user_id", enterprise.UserID)
|
||||
svc.logger.ErrorContext(ctx, "User that created the Android enterprise was not found", "user_id", enterprise.UserID)
|
||||
case err != nil:
|
||||
return ctxerr.Wrap(ctx, err, "getting user")
|
||||
}
|
||||
@@ -692,7 +691,7 @@ func (svc *Service) EnterpriseSignupSSE(ctx context.Context) (chan string, error
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
level.Debug(svc.logger).Log("msg", "Context cancelled during Android signup SSE")
|
||||
svc.logger.DebugContext(ctx, "Context cancelled during Android signup SSE")
|
||||
return
|
||||
case <-time.After(svc.SignupSSEInterval):
|
||||
if svc.signupSSECheck(ctx, done) {
|
||||
@@ -743,24 +742,24 @@ func (svc *Service) verifyEnterpriseExistsWithGoogle(ctx context.Context, enterp
|
||||
case http.StatusNotFound:
|
||||
// Special case: 404 from proxy with deletion confirmation
|
||||
if strings.Contains(gerr.Message, "PROXY_VERIFIED_DELETED:") {
|
||||
level.Info(svc.logger).Log("msg", "enterprise confirmed deleted by proxy", "enterpriseID", enterprise.EnterpriseID)
|
||||
svc.logger.InfoContext(ctx, "enterprise confirmed deleted by proxy", "enterpriseID", enterprise.EnterpriseID)
|
||||
svc.cleanupDeletedEnterprise(ctx, enterprise, enterprise.EnterpriseID)
|
||||
return fleet.NewInvalidArgumentError("enterprise", "Android Enterprise has been deleted").WithStatus(http.StatusNotFound)
|
||||
}
|
||||
case http.StatusBadRequest:
|
||||
// Bad request might indicate missing headers or invalid request format
|
||||
// Don't delete the enterprise in this case
|
||||
level.Error(svc.logger).Log("msg", "bad request when verifying enterprise", "error", err)
|
||||
svc.logger.ErrorContext(ctx, "bad request when verifying enterprise", "error", err)
|
||||
return fmt.Errorf("verifying enterprise with Google: %s (check request headers and format)", err.Error())
|
||||
case http.StatusUnauthorized, http.StatusForbidden:
|
||||
// Authentication/authorization issues - don't delete the enterprise
|
||||
level.Error(svc.logger).Log("msg", "authentication/authorization error when verifying enterprise", "error", err)
|
||||
svc.logger.ErrorContext(ctx, "authentication/authorization error when verifying enterprise", "error", err)
|
||||
return fmt.Errorf("verifying enterprise with Google: authentication error: %w", err)
|
||||
}
|
||||
}
|
||||
// LIST failed - this is likely a technical issue, not deletion
|
||||
// Log the error but don't delete the enterprise
|
||||
level.Error(svc.logger).Log("msg", "failed to list enterprises", "error", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to list enterprises", "error", err)
|
||||
return fmt.Errorf("verifying enterprise with Google: %s", err.Error())
|
||||
}
|
||||
|
||||
@@ -774,7 +773,7 @@ func (svc *Service) verifyEnterpriseExistsWithGoogle(ctx context.Context, enterp
|
||||
}
|
||||
|
||||
// Enterprise NOT in list - it's deleted - perform cleanup
|
||||
level.Info(svc.logger).Log("msg", "enterprise confirmed deleted via LIST API", "enterpriseID", enterpriseID)
|
||||
svc.logger.InfoContext(ctx, "enterprise confirmed deleted via LIST API", "enterpriseID", enterpriseID)
|
||||
svc.cleanupDeletedEnterprise(ctx, enterprise, enterpriseID)
|
||||
return fleet.NewInvalidArgumentError("enterprise", "Android Enterprise has been deleted").WithStatus(http.StatusNotFound)
|
||||
}
|
||||
@@ -799,26 +798,26 @@ func (svc *Service) cleanupDeletedEnterprise(ctx context.Context, enterprise *an
|
||||
// Clean up proxy database records by calling proxy DELETE endpoint
|
||||
// This ensures the proxy won't return conflicts when creating new signup URLs
|
||||
if deleteErr := svc.androidAPIClient.EnterpriseDelete(ctx, enterprise.Name()); deleteErr != nil {
|
||||
level.Warn(svc.logger).Log("msg", "failed to delete proxy records after enterprise deletion (may not exist)", "err", deleteErr)
|
||||
svc.logger.WarnContext(ctx, "failed to delete proxy records after enterprise deletion (may not exist)", "err", deleteErr)
|
||||
}
|
||||
|
||||
// Delete local enterprise records
|
||||
if deleteErr := svc.ds.DeleteAllEnterprises(ctx); deleteErr != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to delete local enterprise records after deletion", "err", deleteErr)
|
||||
svc.logger.ErrorContext(ctx, "failed to delete local enterprise records after deletion", "err", deleteErr)
|
||||
}
|
||||
|
||||
// Turn off Android MDM
|
||||
if setErr := svc.ds.SetAndroidEnabledAndConfigured(ctx, false); setErr != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to turn off Android MDM after enterprise deletion", "err", setErr)
|
||||
svc.logger.ErrorContext(ctx, "failed to turn off Android MDM after enterprise deletion", "err", setErr)
|
||||
}
|
||||
|
||||
// Unenroll Android hosts
|
||||
if unenrollErr := svc.ds.BulkSetAndroidHostsUnenrolled(ctx); unenrollErr != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to unenroll Android hosts after enterprise deletion", "err", unenrollErr)
|
||||
svc.logger.ErrorContext(ctx, "failed to unenroll Android hosts after enterprise deletion", "err", unenrollErr)
|
||||
}
|
||||
|
||||
if err := svc.ds.MarkAllPendingAndroidVPPInstallsAsFailed(ctx); err != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to mark pending Android VPP installs as failed after enterprise deletion", "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to mark pending Android VPP installs as failed after enterprise deletion", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,7 +834,7 @@ func (svc *Service) UnenrollAndroidHost(ctx context.Context, hostID uint) error
|
||||
}
|
||||
|
||||
if !fleet.IsAndroidPlatform(host.Platform) {
|
||||
level.Debug(svc.logger).Log("msg", "Skipping Android unenrollment for non-Android host", "host_id", host.ID, "platform", host.Platform)
|
||||
svc.logger.DebugContext(ctx, "Skipping Android unenrollment for non-Android host", "host_id", host.ID, "platform", host.Platform)
|
||||
return nil // no-op for non-Android hosts
|
||||
}
|
||||
|
||||
@@ -1063,7 +1062,7 @@ func (svc *Service) EnableAppReportsOnDefaultPolicy(ctx context.Context) error {
|
||||
if err != nil {
|
||||
if fleet.IsNotFound(err) {
|
||||
// Then Android MDM isn't setup yet, so no-op
|
||||
level.Info(svc.logger).Log("msg", "skipping android default policy migration, Android MDM is not turned on")
|
||||
svc.logger.InfoContext(ctx, "skipping android default policy migration, Android MDM is not turned on")
|
||||
return nil
|
||||
}
|
||||
return ctxerr.Wrap(ctx, err, "getting android enterprise")
|
||||
@@ -1312,7 +1311,7 @@ func (svc *Service) BuildAndSendFleetAgentConfig(ctx context.Context, enterprise
|
||||
// This prevents concurrent cron runs from processing the same templates
|
||||
certTemplates, err := svc.fleetDS.GetAndTransitionCertificateTemplatesToDelivering(ctx, hostUUID)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to get and transition to delivering", "host_uuid", hostUUID, "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to get and transition to delivering", "host_uuid", hostUUID, "err", err)
|
||||
return ctxerr.Wrapf(ctx, err, "get and transition certificate templates to delivering for host %s", hostUUID)
|
||||
}
|
||||
|
||||
@@ -1325,12 +1324,12 @@ func (svc *Service) BuildAndSendFleetAgentConfig(ctx context.Context, enterprise
|
||||
// There should be no other certificates either, but including them just in case.
|
||||
config, err := buildHostConfig(hostUUID, certTemplates.Templates)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to build host config without certs", "host_uuid", hostUUID, "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to build host config without certs", "host_uuid", hostUUID, "err", err)
|
||||
return ctxerr.Wrapf(ctx, err, "build host config without certs for host %s", hostUUID)
|
||||
}
|
||||
hostConfigs := map[string]android.AgentManagedConfiguration{hostUUID: *config}
|
||||
if err := svc.AddFleetAgentToAndroidPolicy(ctx, enterpriseName, hostConfigs); err != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to send AMAPI config without certs", "host_uuid", hostUUID, "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to send AMAPI config without certs", "host_uuid", hostUUID, "err", err)
|
||||
// Not a critical failure. We will retry installing Fleet Agent when certificates are added to the host's team
|
||||
}
|
||||
continue
|
||||
@@ -1339,16 +1338,16 @@ func (svc *Service) BuildAndSendFleetAgentConfig(ctx context.Context, enterprise
|
||||
// Step 2: Build and send config to AMAPI with ALL certificate templates
|
||||
config, err := buildHostConfig(hostUUID, certTemplates.Templates)
|
||||
if err != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to build host config", "host_uuid", hostUUID, "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to build host config", "host_uuid", hostUUID, "err", err)
|
||||
return ctxerr.Wrapf(ctx, err, "build host config for %s", hostUUID)
|
||||
}
|
||||
|
||||
hostConfigs := map[string]android.AgentManagedConfiguration{hostUUID: *config}
|
||||
if err := svc.AddFleetAgentToAndroidPolicy(ctx, enterpriseName, hostConfigs); err != nil {
|
||||
// AMAPI call failed, revert to pending for retry later
|
||||
level.Error(svc.logger).Log("msg", "failed to send to AMAPI", "host_uuid", hostUUID, "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to send to AMAPI", "host_uuid", hostUUID, "err", err)
|
||||
if revertErr := svc.fleetDS.RevertHostCertificateTemplatesToPending(ctx, hostUUID, certTemplates.DeliveringTemplateIDs); revertErr != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to revert to pending after AMAPI failure", "host_uuid", hostUUID, "err", revertErr)
|
||||
svc.logger.ErrorContext(ctx, "failed to revert to pending after AMAPI failure", "host_uuid", hostUUID, "err", revertErr)
|
||||
return ctxerr.Wrapf(ctx, revertErr, "revert certificate templates to pending after AMAPI failure for host %s", hostUUID)
|
||||
}
|
||||
continue
|
||||
@@ -1356,7 +1355,7 @@ func (svc *Service) BuildAndSendFleetAgentConfig(ctx context.Context, enterprise
|
||||
|
||||
// Step 3: Transition delivering → delivered
|
||||
if err := svc.fleetDS.TransitionCertificateTemplatesToDelivered(ctx, hostUUID, certTemplates.DeliveringTemplateIDs); err != nil {
|
||||
level.Error(svc.logger).Log("msg", "failed to transition to delivered", "host_uuid", hostUUID, "err", err)
|
||||
svc.logger.ErrorContext(ctx, "failed to transition to delivered", "host_uuid", hostUUID, "err", err)
|
||||
return ctxerr.Wrap(ctx, err, "transition certificate templates to delivered")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@@ -18,12 +19,12 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android/service/androidmgmt"
|
||||
ds_mock "github.com/fleetdm/fleet/v4/server/mock"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/endpointer"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/service/middleware/auth"
|
||||
"github.com/fleetdm/fleet/v4/server/service/middleware/log"
|
||||
"github.com/fleetdm/fleet/v4/server/service/modules/activities"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
kitlog "github.com/go-kit/log"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -111,13 +112,14 @@ func (ts *WithServer) SetupSuite(t *testing.T, dbName string) {
|
||||
ts.AndroidAPIClient = android_mock.Client{}
|
||||
ts.createCommonProxyMocks(t)
|
||||
|
||||
logger := kitlog.NewLogfmtLogger(os.Stdout)
|
||||
activityModule := activities.NewActivityModule(&ts.DS.DataStore, logger)
|
||||
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
|
||||
kitLogger := logging.NewLogger(logger)
|
||||
activityModule := activities.NewActivityModule(&ts.DS.DataStore, kitLogger)
|
||||
svc, err := service.NewServiceWithClient(logger, &ts.DS, &ts.AndroidAPIClient, "test-private-key", ts.DS.Datastore, activityModule, config.AndroidAgentConfig{})
|
||||
require.NoError(t, err)
|
||||
ts.Svc = svc
|
||||
|
||||
ts.Server = runServerForTests(t, logger, &ts.FleetSvc, svc)
|
||||
ts.Server = runServerForTests(t, kitLogger, &ts.FleetSvc, svc)
|
||||
}
|
||||
|
||||
func (ts *WithServer) CreateCommonDSMocks() {
|
||||
@@ -206,7 +208,7 @@ func (m *mockService) NewActivity(ctx context.Context, user *fleet.User, details
|
||||
return m.Called(ctx, user, details).Error(0)
|
||||
}
|
||||
|
||||
func runServerForTests(t *testing.T, logger kitlog.Logger, fleetSvc fleet.Service, androidSvc android.Service) *httptest.Server {
|
||||
func runServerForTests(t *testing.T, logger *logging.Logger, fleetSvc fleet.Service, androidSvc android.Service) *httptest.Server {
|
||||
// androidErrorEncoder wraps EncodeError with nil domain encoder for android tests
|
||||
androidErrorEncoder := func(ctx context.Context, err error, w http.ResponseWriter) {
|
||||
endpointer.EncodeError(ctx, err, w, nil)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -13,10 +14,10 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/datastore/mysql"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/android"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/service/contract"
|
||||
"github.com/fleetdm/fleet/v4/server/worker"
|
||||
"github.com/go-kit/log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -431,7 +432,7 @@ func (s *integrationMDMTestSuite) TestCertificateTemplateSpecEndpointAndAMAPIFai
|
||||
// Step: Queue and run the Android setup experience worker job
|
||||
// Note: Pending certificate templates were created above (simulating pubsub). The worker will deliver them.
|
||||
enterpriseName := "enterprises/" + enterpriseID
|
||||
err = worker.QueueRunAndroidSetupExperience(ctx, s.ds, log.NewNopLogger(), host.UUID, &teamID, enterpriseName)
|
||||
err = worker.QueueRunAndroidSetupExperience(ctx, s.ds, slog.New(logging.DiscardHandler{}), host.UUID, &teamID, enterpriseName)
|
||||
require.NoError(t, err)
|
||||
s.runWorker()
|
||||
|
||||
@@ -533,7 +534,7 @@ func (s *integrationMDMTestSuite) TestCertificateTemplateNoTeamWithIDPVariable()
|
||||
// Step: Queue and run the Android setup experience worker job
|
||||
// Note: Pending certificate templates were created above (simulating pubsub). The worker will deliver them.
|
||||
enterpriseName := "enterprises/" + enterpriseID
|
||||
err = worker.QueueRunAndroidSetupExperience(ctx, s.ds, log.NewNopLogger(), host.UUID, nil, enterpriseName)
|
||||
err = worker.QueueRunAndroidSetupExperience(ctx, s.ds, slog.New(logging.DiscardHandler{}), host.UUID, nil, enterpriseName)
|
||||
require.NoError(t, err)
|
||||
s.runWorker()
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ func (s *integrationMDMTestSuite) SetupSuite() {
|
||||
androidMockClient.SetAuthenticationSecretFunc = func(secret string) error {
|
||||
return nil
|
||||
}
|
||||
androidSvc, err := android_service.NewServiceWithClient(wlog, s.ds, androidMockClient, "test-private-key", s.ds, activityModule, config.AndroidAgentConfig{
|
||||
androidSvc, err := android_service.NewServiceWithClient(wlog.SlogLogger(), s.ds, androidMockClient, "test-private-key", s.ds, activityModule, config.AndroidAgentConfig{
|
||||
Package: "com.fleetdm.agent",
|
||||
SigningSHA256: "abc123def456",
|
||||
})
|
||||
@@ -410,7 +410,7 @@ func (s *integrationMDMTestSuite) SetupSuite() {
|
||||
if s.onCleanupScheduleDone != nil {
|
||||
defer s.onCleanupScheduleDone()
|
||||
}
|
||||
return android_service.RenewCertificateTemplates(ctx, ds, logger)
|
||||
return android_service.RenewCertificateTemplates(ctx, ds, logger.SlogLogger())
|
||||
}),
|
||||
)
|
||||
return cleanupsSchedule, nil
|
||||
@@ -432,7 +432,7 @@ func (s *integrationMDMTestSuite) SetupSuite() {
|
||||
s.onAndroidProfileJobDone()
|
||||
}()
|
||||
}
|
||||
err := android_service.ReconcileProfilesWithClient(ctx, ds, logger, "", androidMockClient, config.AndroidAgentConfig{
|
||||
err := android_service.ReconcileProfilesWithClient(ctx, ds, logger.SlogLogger(), "", androidMockClient, config.AndroidAgentConfig{
|
||||
Package: "com.fleetdm.agent",
|
||||
SigningSHA256: "abc123def456",
|
||||
})
|
||||
|
||||
@@ -28,7 +28,7 @@ func SetUpSuite(t *testing.T, uniqueTestName string) *Suite {
|
||||
proxy.InitCommonMocks()
|
||||
activityModule := activities.NewActivityModule(ds, logger)
|
||||
androidSvc, err := android_service.NewServiceWithClient(
|
||||
logger,
|
||||
logger.SlogLogger(),
|
||||
ds,
|
||||
&proxy,
|
||||
"test-private-key",
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
@@ -430,7 +431,7 @@ func buildApplicationPolicyWithConfig(ctx context.Context, appIDs []string,
|
||||
return appPolicies, nil
|
||||
}
|
||||
|
||||
func QueueRunAndroidSetupExperience(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger,
|
||||
func QueueRunAndroidSetupExperience(ctx context.Context, ds fleet.Datastore, logger *slog.Logger,
|
||||
hostUUID string, hostEnrollTeamID *uint, enterpriseName string) error {
|
||||
|
||||
var enrollTeamID uint
|
||||
@@ -449,7 +450,7 @@ func QueueRunAndroidSetupExperience(ctx context.Context, ds fleet.Datastore, log
|
||||
return ctxerr.Wrap(ctx, err, "queueing job")
|
||||
}
|
||||
|
||||
level.Debug(logger).Log("job_id", job.ID, "job_name", softwareWorkerJobName, "task", args.Task)
|
||||
logger.DebugContext(ctx, "queued android setup experience job", "job_id", job.ID, "job_name", softwareWorkerJobName, "task", args.Task)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user