fleet/ee/bulk-operations-dashboard/api/controllers/profiles/upload-profile.js
Eric d8897e0cca
Msp dashboard: Improve speed of profile-related actions (#25221)
Related to: #25170

Changes:
- Updated the `view-profiles`, `get-profiles`, `edit-profile`, and
`upload-profile` actions to send requests to the connected Fleet
instances and process results simultaneously.


I tested these changes while connected to a Fleet instance running on
the same network as my device, here is what I saw:
- Loading the profiles page with four profiles assigned to 22 teams:
	- Current version: 3232ms
	- This PR: 699ms
- Uploading a configuration profile with custom label targets to 22
teams:
	- Current version: 5660ms
	- This PR: 865ms
- Editing a configuration profile that is assigned to 22 teams labels:
	- Current version: 6622ms
	- This PR: 1300ms
- Replacing an existing configuration profile assigned to 22 teams:
	- Current version: 6483ms
	- This PR: 1773ms
- Fetching up-to-date configuration profile information from the Fleet
instance after a change is made:
	- Current version: 2857ms
	- This PR: 736ms
2025-01-14 12:09:23 -06:00

140 lines
4.1 KiB
JavaScript

module.exports = {
friendlyName: 'Upload profile',
description: '',
files: ['newProfile'],
inputs: {
newProfile: {
type: 'ref',
description: 'An Upstream with an incoming file upload.',
required: true,
},
teams: {
type: ['string'],
description: 'An array of team IDs that this profile will be added to'
},
profileTarget: {
type: 'string',
description: 'The target for this configuration profile',
defaultsTo: 'all',
isIn: ['all', 'custom'],
},
labelTargetBehavior: {
type: 'string',
isIn: ['include', 'exclude'],
},
labels: {
type: ['string'],
description: 'A list of the names of labels that will be included/excluded.'
}
},
exits: {
success: {
outputDescription: 'The new profile has been uploaded',
outputType: {},
},
noFileAttached: {
description: 'No file was attached.',
responseType: 'badRequest'
},
tooBig: {
description: 'The file is too big.',
responseType: 'badRequest'
},
},
fn: async function ({newProfile, teams, profileTarget, labelTargetBehavior, labels}) {
let util = require('util');
let profile = await sails.reservoir(newProfile)
.intercept('E_EXCEEDS_UPLOAD_LIMIT', 'tooBig')
.intercept((err)=>new Error('The configuration profile upload failed. '+util.inspect(err)));
if(!profile) {
throw 'noFileAttached';
}
let profileContents = profile[0].contentBytes;
let profileFileName = profile[0].name;
let datelessExtensionlessFilename = profileFileName.replace(/^\d{4}-\d{2}-\d{2}_/, '').replace(/\.[^/.]+$/, '');
let extension = '.'+profileFileName.split('.').pop();
let profilePlatform = 'darwin';
if(_.endsWith(profileFileName, '.xml')) {
profilePlatform = 'windows';
}
let profileToReturn;
let newProfileInfo = {
name: datelessExtensionlessFilename,
platform: profilePlatform,
profileType: extension,
createdAt: Date.now(),
profileTarget,
labels,
labelTargetBehavior,
};
if(!teams) {
newProfileInfo.profileContents = profileContents;
profileToReturn = await UndeployedProfile.create(newProfileInfo).fetch();
} else {
let newTeams = [];
await sails.helpers.flow.simultaneouslyForEach(teams, async (teamApid)=>{
let bodyForThisRequest = {
team_id: teamApid,// eslint-disable-line camelcase
labels_exclude_any: labelTargetBehavior === 'exclude' ? labels : undefined,// eslint-disable-line camelcase
labels_include_all: labelTargetBehavior === 'include' ? labels : undefined,// eslint-disable-line camelcase
profile: {
options: {
filename: profileFileName,
contentType: 'application/octet-stream'
},
value: profileContents,
}
};
let newProfileResponse = await sails.helpers.http.sendHttpRequest.with({
method: 'POST',
baseUrl: sails.config.custom.fleetBaseUrl,
url: `/api/v1/fleet/configuration_profiles?team_id=${teamApid}`,
enctype: 'multipart/form-data',
body: bodyForThisRequest,
headers: {
Authorization: `Bearer ${sails.config.custom.fleetApiToken}`,
},
});
let parsedJsonResponse = JSON.parse(newProfileResponse.body);
let uuidForThisProfile = parsedJsonResponse.profile_uuid;
// send a request to the Fleet instance to get the bundleId of the new profile.
await sails.helpers.http.get.with({
baseUrl: sails.config.custom.fleetBaseUrl,
url: `/api/v1/fleet/configuration_profiles/${uuidForThisProfile}`,
headers: {
Authorization: `Bearer ${sails.config.custom.fleetApiToken}`,
}
});
newTeams.push({
fleetApid: teamApid,
uuid: JSON.parse(newProfileResponse.body).profile_uuid
});
});
newProfileInfo.teams = newTeams;
profileToReturn = newProfileInfo;
}
// All done.
return profileToReturn;
}
};