/* Copyright (C) 2017 Cloudbase Solutions SRL This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // @flow import moment from 'moment' import AzureApiCaller from '../utils/AzureApiCaller' import type { Assessment, VmItem, VmSize } from '../types/Assessment' // $FlowIgnore const resourceGroupsUrl = ({ subscriptionId }) => `/subscriptions/${subscriptionId}/resourceGroups` const projectsUrl = ({ resourceGroupName, ...other }) => `${resourceGroupsUrl({ ...other })}/${resourceGroupName}/providers/Microsoft.Migrate/projects` const groupsUrl = ({ projectName, ...other }) => `${projectsUrl({ ...other })}/${projectName}/groups` const assessmentsUrl = ({ groupName, ...other }) => `${groupsUrl({ ...other })}/${groupName}/assessments` const assessmentDetailsUrl = ({ assessmentName, ...other }) => `${assessmentsUrl({ ...other })}/${assessmentName}` const assessedVmsUrl = ({ ...other }) => `${assessmentDetailsUrl({ ...other })}/assessedMachines` class AzureSourceUtil { static sortAssessments(assessments) { assessments.sort((a, b) => { return moment(b.properties.updatedTimestamp).toDate().getTime() - moment(a.properties.updatedTimestamp) }) return assessments } static checkQueues(queues, requestIds, callback) { if (requestIds[0] !== requestIds[1]) { return } let doneQeues = queues.filter(q => q === 0).length if (doneQeues === queues.length) { callback() } } } class AzureSource { static authenticate(username: string, password: string): Promise { return new Promise((resolve, reject) => { AzureApiCaller.send({ url: '/azure-login', method: 'POST', data: { username, password }, }).then(response => { let entries = Object.keys(response.tokenCache)[0] let accessToken = response.tokenCache[entries][0].accessToken AzureApiCaller.setHeader('Authorization', `Bearer ${accessToken}`) resolve(response) }, reject) }) } static getResourceGroups(subscriptionId: string): Promise<$PropertyType[]> { return new Promise((resolve, reject) => { AzureApiCaller.send({ url: resourceGroupsUrl({ subscriptionId }), }, '2017-08-01').then(response => { resolve(response.value) }, reject) }) } static reqId: string static getAssessments(subscriptionId: string, resourceGroupName: string): Promise { this.reqId = subscriptionId + resourceGroupName return new Promise((resolve, reject) => { let assessments = [] let projectsQueue let groupsQueue = 0 // Load projects AzureApiCaller.send({ url: projectsUrl({ resourceGroupName, subscriptionId }), }).then(response => { let projects = response.value projectsQueue = projects.length if (projectsQueue === 0 && subscriptionId + resourceGroupName === this.reqId) { resolve([]) } projects.forEach(project => { if (project.type !== 'Microsoft.Migrate/projects') { return } // Load Groups AzureApiCaller.send({ url: groupsUrl({ projectName: project.name, subscriptionId, resourceGroupName }), }).then(response => { projectsQueue -= 1 let groups = response.value groupsQueue = groups.length if (groupsQueue === 0 && subscriptionId + resourceGroupName === this.reqId) { resolve([]) } groups.forEach(group => { // Load Assessments AzureApiCaller.send({ url: assessmentsUrl({ subscriptionId, resourceGroupName, projectName: project.name, groupName: group.name }), }).then(response => { groupsQueue -= 1 assessments = assessments.concat(response.value.map(a => ({ ...a, project, group }))) AzureSourceUtil.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(AzureSourceUtil.sortAssessments(assessments)) }) }, () => { groupsQueue -= 1; AzureSourceUtil.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(AzureSourceUtil.sortAssessments(assessments)) }) }) }) }, () => { projectsQueue -= 1; AzureSourceUtil.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(AzureSourceUtil.sortAssessments(assessments)) }) }) }) }, reject) }) } static getAssessmentDetails(info: Assessment): Promise { return new Promise((resolve, reject) => { AzureApiCaller.send({ url: assessmentDetailsUrl({ ...info, subscriptionId: info.connectionInfo.subscription_id }), }).then(response => { let assessment = { ...response, ...info } resolve(assessment) }, reject) }) } static getAssessedVms(info: Assessment): Promise { return new Promise((resolve, reject) => { AzureApiCaller.send({ url: assessedVmsUrl({ ...info, subscriptionId: info.connectionInfo.subscription_id }), }).then(response => { let vms = response.value vms.sort((a, b) => { let getLabel = item => `${item.properties.datacenterContainer}/${item.properties.displayName}` return getLabel(a).localeCompare(getLabel(b)) }) resolve(vms) }, reject) }) } static getVmSizes(info: Assessment): Promise { return new Promise((resolve, reject) => { AzureApiCaller.send({ // $FlowIgnore url: `/subscriptions/${info.connectionInfo.subscription_id}/providers/Microsoft.Compute/locations/${info.location}/vmSizes`, }, '2017-12-01').then(response => { resolve(response.value) }, reject) }) } } export default AzureSource