Files
fleet/website/api/controllers/android-proxy/create-android-signup-url.js
Eric f145c778b8 Website: log number of android enterprise requests in the past minute (#50780)
Related to: https://github.com/fleetdm/fleet/issues/49212

Changes:
- Updated the custom hook to create `sails.androidProxyApiRequestCount`,
and to log and reset the value every minute
- Updated android proxy endpoints to increment
`sails.androidProxyApiRequestCount` every time a request to the Android
management API is sent

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Monitoring**
* Added comprehensive tracking for Android Management API requests
across enrollment, enterprise, device, application, policy, and command
operations.
* Added periodic request-count logging and automatic resets when Android
Enterprise credentials are configured.
* Improved reporting alignment with minute-based API limits while
keeping logs quiet during periods without requests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-07 11:58:35 -05:00

96 lines
4.8 KiB
JavaScript
Vendored

module.exports = {
friendlyName: 'Create android signup url',
description: 'Creates and returns a signup URL for an android enterprise.',
inputs: {
callbackUrl: {
type: 'string',
required: true,
}
},
exits: {
success: { description: 'A signup URL has been sent to the requesting Fleet server.'},
missingOriginHeader: { description: 'The request was missing an Origin header', responseType: 'badRequest'},
enterpriseAlreadyExists: { description: 'An Android enterprise already exists for this Fleet instance.', statusCode: 409 },
invalidCallbackUrl: { description: 'The provided callbackUrl could not be used to create an Android enterprise signup URL.', responseType: 'badRequest'}
},
fn: async function ({ callbackUrl }) {
// Parse the Fleet server url from the origin header.
let fleetServerUrl = this.req.get('Origin');
if(!fleetServerUrl){
throw 'missingOriginHeader';
}
// Check the database for an existing record for this Fleet server.
let connectionforThisInstanceExists = await AndroidEnterprise.findOne({fleetServerUrl: fleetServerUrl});
if(connectionforThisInstanceExists) {
// Before throwing conflict, verify the enterprise still exists in Google
// If it doesn't exist, clean up the stale proxy record and continue with signup
let isEnterpriseManagedByFleet = await sails.helpers.androidProxy.getIsEnterpriseManagedByFleet(connectionforThisInstanceExists.androidEnterpriseId)
.intercept({status: 429}, (err)=>{
// If the Android management API returns a 429 response, log an additional warning that will trigger a help-p1 alert.
sails.log.warn(`p1: Android management API rate limit exceeded!`);
return new Error(`When attempting to create a signup url for a new Android enterprise, an error occurred. Error: ${err}`);
});
if(isEnterpriseManagedByFleet) {
// Enterprise still exists in Google - throw conflict
throw 'enterpriseAlreadyExists';
} else {
// Enterprise not found in LIST - clean up stale proxy record
await AndroidEnterprise.destroyOne({ id: connectionforThisInstanceExists.id });
// Continue with signup process (don't throw conflict)
}
}
// Get the shared Google API auth client with the getAndroidManagementAuthorizationClient helper.
// Note: we are doing this outside of the sails.helpers.flow.build() so any errors related to the website's credentials returned by the helper are not intercepted.
let androidManagementAuthClient = await sails.helpers.androidProxy.getAndroidManagementAuthorizationClient();
// Get a signup url for this Android enterprise.
// Note: We're using sails.helpers.flow.build here to handle any errors that occurr using google's node library.
let signupUrl = await sails.helpers.flow.build(async ()=>{
let { google } = require('googleapis');
let androidManagementConnection = google.androidmanagement({version: 'v1', auth: androidManagementAuthClient});
// [?] https://googleapis.dev/nodejs/googleapis/latest/androidmanagement/classes/Resource$Signupurls.html#create
sails.androidProxyApiRequestCount++;// Count this Android Management API request toward the per-minute total logged in api/hooks/custom/index.js.
let createSignupUrlResponse = await androidManagementConnection.signupUrls.create({
// The callback URL that the admin will be redirected to after successfully creating an enterprise. Before redirecting there the system will add a query parameter to this URL named enterpriseToken which will contain an opaque token to be used for the create enterprise request. The URL will be parsed then reformatted in order to add the enterpriseToken parameter, so there may be some minor formatting changes.
callbackUrl: callbackUrl,
// The ID of the Google Cloud Platform project which will own the enterprise.
projectId: sails.config.custom.androidEnterpriseProjectId,
});
return createSignupUrlResponse.data;
}).intercept({status: 400}, (unusedErr)=>{
return {'invalidCallbackUrl': 'The provided Callback Url could not be used to create an Android enterprise signup URL.'};
}).intercept({status: 429}, (err)=>{
// If the Android management API returns a 429 response, log an additional warning that will trigger a help-p1 alert.
sails.log.warn(`p1: Android management API rate limit exceeded!`);
return new Error(`When attempting to create a singup url for a new Android enterprise, an error occurred. Error: ${err}`);
}).intercept((err)=>{
return new Error(`When attempting to create a singup url for a new Android enterprise, an error occurred. Error: ${require('util').inspect(err)}`);
});
return {
url: signupUrl.url,
name: signupUrl.name,
};
}
};