AzureSource.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. Copyright (C) 2017 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. // @flow
  15. import moment from 'moment'
  16. import AzureApiCaller from '../utils/AzureApiCaller'
  17. import type { Assessment, VmItem, VmSize } from '../types/Assessment'
  18. // $FlowIgnore
  19. const resourceGroupsUrl = ({ subscriptionId }) => `/subscriptions/${subscriptionId}/resourceGroups`
  20. const projectsUrl = ({ resourceGroupName, ...other }) => `${resourceGroupsUrl({ ...other })}/${resourceGroupName}/providers/Microsoft.Migrate/projects`
  21. const groupsUrl = ({ projectName, ...other }) => `${projectsUrl({ ...other })}/${projectName}/groups`
  22. const assessmentsUrl = ({ groupName, ...other }) => `${groupsUrl({ ...other })}/${groupName}/assessments`
  23. const assessmentDetailsUrl = ({ assessmentName, ...other }) => `${assessmentsUrl({ ...other })}/${assessmentName}`
  24. const assessedVmsUrl = ({ ...other }) => `${assessmentDetailsUrl({ ...other })}/assessedMachines`
  25. class AzureSourceUtil {
  26. static sortAssessments(assessments) {
  27. assessments.sort((a, b) => {
  28. return moment(b.properties.updatedTimestamp).toDate().getTime() - moment(a.properties.updatedTimestamp)
  29. })
  30. return assessments
  31. }
  32. static checkQueues(queues, requestIds, callback) {
  33. if (requestIds[0] !== requestIds[1]) {
  34. return
  35. }
  36. let doneQeues = queues.filter(q => q === 0).length
  37. if (doneQeues === queues.length) {
  38. callback()
  39. }
  40. }
  41. }
  42. class AzureSource {
  43. static authenticate(username: string, password: string): Promise<any> {
  44. return new Promise((resolve, reject) => {
  45. AzureApiCaller.send({
  46. url: '/azure-login',
  47. method: 'POST',
  48. data: { username, password },
  49. }).then(response => {
  50. let entries = Object.keys(response.tokenCache)[0]
  51. let accessToken = response.tokenCache[entries][0].accessToken
  52. AzureApiCaller.setHeader('Authorization', `Bearer ${accessToken}`)
  53. resolve(response)
  54. }, reject)
  55. })
  56. }
  57. static getResourceGroups(subscriptionId: string): Promise<$PropertyType<Assessment, 'group'>[]> {
  58. return new Promise((resolve, reject) => {
  59. AzureApiCaller.send({
  60. url: resourceGroupsUrl({ subscriptionId }),
  61. }, '2017-08-01').then(response => {
  62. resolve(response.value)
  63. }, reject)
  64. })
  65. }
  66. static reqId: string
  67. static getAssessments(subscriptionId: string, resourceGroupName: string): Promise<Assessment[]> {
  68. this.reqId = subscriptionId + resourceGroupName
  69. return new Promise((resolve, reject) => {
  70. let assessments = []
  71. let projectsQueue
  72. let groupsQueue = 0
  73. // Load projects
  74. AzureApiCaller.send({
  75. url: projectsUrl({ resourceGroupName, subscriptionId }),
  76. }).then(response => {
  77. let projects = response.value
  78. projectsQueue = projects.length
  79. if (projectsQueue === 0 && subscriptionId + resourceGroupName === this.reqId) {
  80. resolve([])
  81. }
  82. projects.forEach(project => {
  83. if (project.type !== 'Microsoft.Migrate/projects') {
  84. return
  85. }
  86. // Load Groups
  87. AzureApiCaller.send({
  88. url: groupsUrl({ projectName: project.name, subscriptionId, resourceGroupName }),
  89. }).then(response => {
  90. projectsQueue -= 1
  91. let groups = response.value
  92. groupsQueue = groups.length
  93. if (groupsQueue === 0 && subscriptionId + resourceGroupName === this.reqId) {
  94. resolve([])
  95. }
  96. groups.forEach(group => {
  97. // Load Assessments
  98. AzureApiCaller.send({
  99. url: assessmentsUrl({ subscriptionId, resourceGroupName, projectName: project.name, groupName: group.name }),
  100. }).then(response => {
  101. groupsQueue -= 1
  102. assessments = assessments.concat(response.value.map(a => ({ ...a, project, group })))
  103. AzureSourceUtil.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(AzureSourceUtil.sortAssessments(assessments)) })
  104. }, () => { groupsQueue -= 1; AzureSourceUtil.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(AzureSourceUtil.sortAssessments(assessments)) }) })
  105. })
  106. }, () => { projectsQueue -= 1; AzureSourceUtil.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(AzureSourceUtil.sortAssessments(assessments)) }) })
  107. })
  108. }, reject)
  109. })
  110. }
  111. static getAssessmentDetails(info: Assessment): Promise<Assessment> {
  112. return new Promise((resolve, reject) => {
  113. AzureApiCaller.send({
  114. url: assessmentDetailsUrl({ ...info, subscriptionId: info.connectionInfo.subscription_id }),
  115. }).then(response => {
  116. let assessment = { ...response, ...info }
  117. resolve(assessment)
  118. }, reject)
  119. })
  120. }
  121. static getAssessedVms(info: Assessment): Promise<VmItem[]> {
  122. return new Promise((resolve, reject) => {
  123. AzureApiCaller.send({
  124. url: assessedVmsUrl({ ...info, subscriptionId: info.connectionInfo.subscription_id }),
  125. }).then(response => {
  126. let vms = response.value
  127. vms.sort((a, b) => {
  128. let getLabel = item => `${item.properties.datacenterContainer}/${item.properties.displayName}`
  129. return getLabel(a).localeCompare(getLabel(b))
  130. })
  131. resolve(vms)
  132. }, reject)
  133. })
  134. }
  135. static getVmSizes(info: Assessment): Promise<VmSize[]> {
  136. return new Promise((resolve, reject) => {
  137. AzureApiCaller.send({
  138. // $FlowIgnore
  139. url: `/subscriptions/${info.connectionInfo.subscription_id}/providers/Microsoft.Compute/locations/${info.location}/vmSizes`,
  140. }, '2017-12-01').then(response => {
  141. resolve(response.value)
  142. }, reject)
  143. })
  144. }
  145. }
  146. export default AzureSource