mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Msp dashboard: Update software endpoints (#24299)
Changes: - Updated the software page to display different error messages when requests to software endpoints fail. - Updated the edit software endpoint to: - have three new exits, `softwareAlreadyExistsOnThisTeam`, `couldNotReadVersion` and `softwareDeletionFailed` - Create database records for newly undeployed software after it has been removed from all teams on a Fleet instance. - Return a `softwareAlreadyExistsOnThisTeam` response if undeployed software is being transferred to a team it is already deployed to. - Return a `couldNotReadVersion` response if the Fleet instance cannot read the version information from an uploaded software installer - Return a `softwareDeletionFailed` response if an installer cannot be deleted via an API request (If it is configured to be installed during the macOS setup experience) - Updated the upload-software endpoint to return a `couldNotReadVersion` response if the Fleet instance cannot read the version information from an uploaded software installer
This commit is contained in:
parent
511ffd144f
commit
93d6c029f4
3 changed files with 124 additions and 20 deletions
|
|
@ -46,9 +46,23 @@ module.exports = {
|
|||
description: 'The provided replacement software\'s has the wrong extension.',
|
||||
statusCode: 400,
|
||||
},
|
||||
|
||||
softwareUploadFailed: {
|
||||
description: 'The software upload failed'
|
||||
}
|
||||
},
|
||||
|
||||
softwareAlreadyExistsOnThisTeam: {
|
||||
description: 'A software installer with this name already exists on the Fleet Instance',
|
||||
},
|
||||
|
||||
couldNotReadVersion: {
|
||||
description:'Fleet could not read version information from the provided software installer.'
|
||||
},
|
||||
|
||||
softwareDeletionFailed: {
|
||||
description: 'The specified software could not be deleted from the Fleet instance.',
|
||||
statusCode: 409,
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -167,7 +181,35 @@ module.exports = {
|
|||
}
|
||||
};
|
||||
},
|
||||
})
|
||||
}
|
||||
)
|
||||
.intercept({response: {status: 409}}, async (error)=>{// handles errors related to duplicate software items.
|
||||
if(!software.id) {// If the software does not have an ID, it not stored in the app's database/s3 bucket, so we can safely delete the file in s3.
|
||||
await sails.rm(sails.config.uploads.prefixForFileDeletion+softwareFd);
|
||||
}
|
||||
return {'softwareAlreadyExistsOnThisTeam': error};
|
||||
})
|
||||
.intercept({name: 'AxiosError', response: {status: 400}}, async (error)=>{// Handles errors related to malformed installer packages
|
||||
if(!software.id) {// If the software does not have an ID, it not stored in the app's database/s3 bucket, so we can safely delete the file in s3.
|
||||
await sails.rm(sails.config.uploads.prefixForFileDeletion+softwareFd);
|
||||
}
|
||||
let axiosError = error;
|
||||
if(axiosError.response.data) {
|
||||
if(axiosError.response.data.errors && _.isArray(axiosError.response.data.errors)){
|
||||
if(axiosError.response.data.errors[0] && axiosError.response.data.errors[0].reason) {
|
||||
let errorMessageFromFleetInstance = axiosError.response.data.errors[0].reason;
|
||||
if(_.startsWith(errorMessageFromFleetInstance, `Couldn't add. Fleet couldn't read the version`)){
|
||||
return 'couldNotReadVersion';
|
||||
} else {
|
||||
sails.log.warn(`When attempting to upload a software installer, an unexpected error occurred communicating with the Fleet API. Error returned from Fleet API: ${errorMessageFromFleetInstance}`);
|
||||
return {'softwareUploadFailed': error};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sails.log.warn(`When attempting to upload a software installer, an unexpected error occurred communicating with the Fleet API, ${require('util').inspect(error, {depth: 3})}`);
|
||||
return {'softwareUploadFailed': error};
|
||||
})
|
||||
.intercept(async (error)=>{
|
||||
// Note: with this current behavior, all errors from this upload are currently swallowed and a softwareUploadFailed response is returned.
|
||||
// FUTURE: Test to make sure that uploading duplicate software to a team results in a 409 response.
|
||||
|
|
@ -234,6 +276,33 @@ module.exports = {
|
|||
};
|
||||
},
|
||||
})
|
||||
.intercept({response: {status: 409}}, async (error)=>{// handles errors related to duplicate software items.
|
||||
if(!software.id) {// If the software does not have an ID, it not stored in the app's database/s3 bucket, so we can safely delete the file in s3.
|
||||
await sails.rm(sails.config.uploads.prefixForFileDeletion+softwareFd);
|
||||
}
|
||||
return {'softwareAlreadyExistsOnThisTeam': error};
|
||||
})
|
||||
.intercept({name: 'AxiosError', response: {status: 400}}, async (error)=>{// Handles errors related to malformed installer packages
|
||||
if(!software.id) {// If the software does not have an ID, it not stored in the app's database/s3 bucket, so we can safely delete the file in s3.
|
||||
await sails.rm(sails.config.uploads.prefixForFileDeletion+softwareFd);
|
||||
}
|
||||
let axiosError = error;
|
||||
if(axiosError.response.data) {
|
||||
if(axiosError.response.data.errors && _.isArray(axiosError.response.data.errors)){
|
||||
if(axiosError.response.data.errors[0] && axiosError.response.data.errors[0].reason) {
|
||||
let errorMessageFromFleetInstance = axiosError.response.data.errors[0].reason;
|
||||
if(_.startsWith(errorMessageFromFleetInstance, `Couldn't add. Fleet couldn't read the version`)){
|
||||
return 'couldNotReadVersion';
|
||||
} else {
|
||||
sails.log.warn(`When attempting to upload a software installer, an unexpected error occurred communicating with the Fleet API. Error returned from Fleet API: ${errorMessageFromFleetInstance}`);
|
||||
return {'softwareUploadFailed': error};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sails.log.warn(`When attempting to upload a software installer, an unexpected error occurred communicating with the Fleet API, ${require('util').inspect(error, {depth: 3})}`);
|
||||
return {'softwareUploadFailed': error};
|
||||
})
|
||||
.intercept(async (error)=>{
|
||||
// Note: with this current behavior, all errors from this upload are currently swallowed and a softwareUploadFailed response is returned.
|
||||
// FUTURE: Test to make sure that uploading duplicate software to a team results in a 409 response.
|
||||
|
|
@ -279,6 +348,11 @@ module.exports = {
|
|||
headers: {
|
||||
Authorization: `Bearer ${sails.config.custom.fleetApiToken}`,
|
||||
}
|
||||
})
|
||||
.intercept({raw:{statusCode: 409}}, (error)=>{
|
||||
// If the Fleet instance's returns a 409 response, then the software is configured to be installed as
|
||||
// part of the macOS setup experience, and must be removed before it can be deleted via API requests.
|
||||
return {softwareDeletionFailed: error};
|
||||
});
|
||||
}
|
||||
// If the software had been previously undeployed, delete the installer in s3 and the db record.
|
||||
|
|
@ -289,9 +363,23 @@ module.exports = {
|
|||
|
||||
} else if(software.teams && newTeamIds.length === 0) {
|
||||
// If this is a deployed software that is being unassigned, save information about the uploaded file in our s3 bucket.
|
||||
for(let team of software.teams) {
|
||||
// Now delete the software on the Fleet instance.
|
||||
await sails.helpers.http.sendHttpRequest.with({
|
||||
method: 'DELETE',
|
||||
baseUrl: sails.config.custom.fleetBaseUrl,
|
||||
url: `/api/v1/fleet/software/titles/${software.fleetApid}/available_for_install?team_id=${team.fleetApid}`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${sails.config.custom.fleetApiToken}`,
|
||||
}
|
||||
})
|
||||
.intercept({raw:{statusCode: 409}}, (error)=>{
|
||||
// If the Fleet instance's returns a 409 response, then the software is configured to be installed as
|
||||
// part of the macOS setup experience, and must be removed before it can be deleted via API requests.
|
||||
return {softwareDeletionFailed: error};
|
||||
});
|
||||
}
|
||||
if(newSoftware) {
|
||||
// remove the old copy.
|
||||
// console.log('Removing old package for ',softwareName);
|
||||
await UndeployedSoftware.create({
|
||||
uploadFd: softwareFd,
|
||||
uploadMime: softwareMime,
|
||||
|
|
@ -315,17 +403,6 @@ module.exports = {
|
|||
uninstallScript,
|
||||
});
|
||||
}
|
||||
// Now delete the software on the Fleet instance.
|
||||
for(let team of software.teams) {
|
||||
await sails.helpers.http.sendHttpRequest.with({
|
||||
method: 'DELETE',
|
||||
baseUrl: sails.config.custom.fleetBaseUrl,
|
||||
url: `/api/v1/fleet/software/titles/${software.fleetApid}/available_for_install?team_id=${team.fleetApid}`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${sails.config.custom.fleetApiToken}`,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
// console.log('updating existing db record!');
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ module.exports = {
|
|||
|
||||
softwareUploadFailed: {
|
||||
description:'An unexpected error occurred communicating with the Fleet API'
|
||||
},
|
||||
|
||||
couldNotReadVersion: {
|
||||
description:'Fleet could not read version information from the provided software installer.'
|
||||
}
|
||||
|
||||
},
|
||||
|
|
@ -100,13 +104,32 @@ module.exports = {
|
|||
};
|
||||
}
|
||||
})
|
||||
.intercept({response: {status: 409}}, async (error)=>{
|
||||
.intercept({response: {status: 409}}, async (error)=>{// handles errors related to duplicate software items.
|
||||
await sails.rm(sails.config.uploads.prefixForFileDeletion+uploadedSoftware.fd);
|
||||
return {'softwareAlreadyExistsOnThisTeam': error};
|
||||
})
|
||||
.intercept({name: 'AxiosError'}, async (error)=>{
|
||||
.intercept({name: 'AxiosError', response: {status: 400}}, async (error)=>{// Handles errors related to malformed installer packages
|
||||
await sails.rm(sails.config.uploads.prefixForFileDeletion+uploadedSoftware.fd);
|
||||
sails.log.warn(`When attempting to upload a software installer, an unexpected error occurred communicating with the Fleet API, ${require('util').inspect(error, {depth: 2})}`);
|
||||
let axiosError = error;
|
||||
if(axiosError.response.data) {
|
||||
if(axiosError.response.data.errors && _.isArray(axiosError.response.data.errors)){
|
||||
if(axiosError.response.data.errors[0] && axiosError.response.data.errors[0].reason) {
|
||||
let errorMessageFromFleetInstance = axiosError.response.data.errors[0].reason;
|
||||
if(_.startsWith(errorMessageFromFleetInstance, `Couldn't add. Fleet couldn't read the version`)){
|
||||
return 'couldNotReadVersion';
|
||||
} else {
|
||||
sails.log.warn(`When attempting to upload a software installer, an unexpected error occurred communicating with the Fleet API. Error returned from Fleet API: ${errorMessageFromFleetInstance}`);
|
||||
return {'softwareUploadFailed': error};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sails.log.warn(`When attempting to upload a software installer, an unexpected error occurred communicating with the Fleet API, ${require('util').inspect(error, {depth: 3})}`);
|
||||
return {'softwareUploadFailed': error};
|
||||
})
|
||||
.intercept({name: 'AxiosError'}, async (error)=>{// Handles any other error.
|
||||
await sails.rm(sails.config.uploads.prefixForFileDeletion+uploadedSoftware.fd);
|
||||
sails.log.warn(`When attempting to upload a software installer, an unexpected error occurred communicating with the Fleet API, ${require('util').inspect(error, {depth: 3})}`);
|
||||
return {'softwareUploadFailed': error};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,8 +145,11 @@
|
|||
<p class="mb-2"><strong>Teams</strong></p>
|
||||
<multifield :value="formData.teams" v-model="formData.newTeamIds" input-type="teamSelect" :select-options="teams" add-button-text="Add team"></multifield>
|
||||
</div>
|
||||
<cloud-error v-if="cloudError && cloudError.exit === 'wrongInstallerExtension'">{{cloudError.responseInfo.body}}</cloud-error>
|
||||
<cloud-error v-else-if="cloudError"></cloud-error>
|
||||
<cloud-error class="mb-2" v-if="cloudError && cloudError.exit === 'wrongInstallerExtension'">{{cloudError.responseInfo.body}}</cloud-error>
|
||||
<cloud-error class="mb-2" v-else-if="cloudError && cloudError === 'couldNotReadVersion'">The Fleet instance could not read version information from the provided software installer.</cloud-error>
|
||||
<cloud-error class="mb-2" v-else-if="cloudError && cloudError === 'softwareDeletionFailed'">This software has been configured to be installed as part of the macOS setup experience and cannot be removed from a team. Please remove this software from any teams you want to remove this from in the <a :href="`${fleetBaseUrl}/controls/setup-experience/install-software`" target="_blank">"Setup experience" tab of the Controls page</a> on your Fleet instance and try again </cloud-error>
|
||||
<cloud-error class="mb-2" v-else-if="cloudError && cloudError === 'softwareAlreadyExistsOnThisTeam'">An error occured when transfering this software to a new team. A software installer with the same name as this software already exists on one or more of the selected teams.</cloud-error>
|
||||
<cloud-error class="mb-2" v-else-if="cloudError"></cloud-error>
|
||||
<div purpose="modal-buttons" class="d-flex flex-row justify-content-end align-items-center">
|
||||
<ajax-button :syncing.sync="syncing" purpose="modal-button" type="submit">Save</ajax-button>
|
||||
</div>
|
||||
|
|
@ -189,6 +192,7 @@
|
|||
</div>
|
||||
<div class="invalid-feedback text-center" v-if="formErrors.teams">Please select the teams you want to deploy this software to.</div>
|
||||
<cloud-error v-if="cloudError && cloudError === 'softwareAlreadyExistsOnThisTeam'">A software with the same name as the uploaded software already exists on one or more of the selected teams.</cloud-error>
|
||||
<cloud-error v-if="cloudError && cloudError === 'couldNotReadVersion'">The Fleet instance could not read version information from the provided software installer.</cloud-error>
|
||||
<cloud-error v-else-if="cloudError"></cloud-error>
|
||||
<div purpose="modal-buttons" class="d-flex flex-row justify-content-end align-items-center">
|
||||
<a purpose="cancel-button" @click="closeModal()">Cancel</a>
|
||||
|
|
|
|||
Loading…
Reference in a new issue