Преглед изворни кода

Replace Azure's API caller with the generic one

Remove the API caller made for Azure and use instead the generic one,
this also removes `ajax-request` dependency.
Replace `request` library with `axios` in the server proxy (currently
used only by Azure), thus removing dependency on `request` and using the
available `axios` library.
Sergiu Miclea пре 8 година
родитељ
комит
b1ced2f9a0
6 измењених фајлова са 78 додато и 168 уклоњено
  1. 0 2
      package.json
  2. 15 8
      server/proxy.js
  3. 61 42
      src/sources/AzureSource.js
  4. 2 1
      src/types/Assessment.js
  5. 0 91
      src/utils/AzureApiCaller.js
  6. 0 24
      yarn.lock

+ 0 - 2
package.json

@@ -54,7 +54,6 @@
   },
   "dependencies": {
     "@webpack-blocks/webpack2": "^0.4.0",
-    "ajax-request": "^1.2.3",
     "axios": "^0.18.0",
     "babel-core": "^6.26.0",
     "babel-loader": "^7.1.2",
@@ -93,7 +92,6 @@
     "react-notification-system": "^0.2.15",
     "react-router-dom": "^4.2.2",
     "react-tooltip": "^3.4.0",
-    "request": "^2.83.0",
     "rimraf": "^2.6.2",
     "styled-components": "2.2.0",
     "styled-tools": "^0.2.2",

+ 15 - 8
server/proxy.js

@@ -14,10 +14,16 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import MsRest from 'ms-rest-azure'
 import bodyParser from 'body-parser'
-import request from 'request'
+import axios from 'axios'
 
 const forwardHeaders = ['authorization']
 
+let buildError = (status, message) => {
+  return {
+    error: { message: `Proxy - ${message}` },
+  }
+}
+
 module.exports = app => {
   const jsonParser = bodyParser.json()
 
@@ -40,14 +46,15 @@ module.exports = app => {
       }
     })
 
-    request({
-      url,
-      headers,
-    }, (err, resp, body) => {
-      if (!err) {
-        res.send(body)
+    axios({ url, headers }).then(response => {
+      res.send(response.data)
+    }).catch(error => {
+      if (error.response) {
+        res.status(error.response.status).send(buildError(error.response.status, error.response.data.error.message))
+      } else if (error.request) {
+        res.status(500).send(buildError(500, 'No Response!'))
       } else {
-        res.status(500).send(err)
+        res.status(500).send(buildError(500, 'Error creating request!'))
       }
     })
   })

+ 61 - 42
src/sources/AzureSource.js

@@ -16,18 +16,25 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import moment from 'moment'
 
-import AzureApiCaller from '../utils/AzureApiCaller'
+import Api from '../utils/ApiCaller'
 import type { Assessment, VmItem, VmSize } from '../types/Assessment'
 
-// $FlowIgnore
-const resourceGroupsUrl = ({ subscriptionId }) => `/subscriptions/${subscriptionId}/resourceGroups`
+const azureUrl = 'https://management.azure.com/'
+const defaultApiVersion = '2017-11-11-preview'
+
+const resourceGroupsUrl = (opts: { subscriptionId: string }) => `/subscriptions/${opts.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 {
+class Util {
+  static buildUrl(baseUrl: string, apiVersion?: string): string {
+    const url = `/proxy/${azureUrl + baseUrl}?api-version=${apiVersion || defaultApiVersion}`
+    return url
+  }
+
   static sortAssessments(assessments) {
     assessments.sort((a, b) => {
       return moment(b.properties.updatedTimestamp).toDate().getTime() - moment(a.properties.updatedTimestamp)
@@ -45,30 +52,42 @@ class AzureSourceUtil {
       callback()
     }
   }
+
+  static responseIsValid(resolve, reject, response, resolveData) {
+    if (response.data.error) {
+      const error = response.data.error
+      console.error('%c', 'color: #D0021B', `${error.code}: ${error.message}`)
+      reject()
+      return false
+    }
+
+    if (resolveData) {
+      resolve(resolveData)
+    }
+    return true
+  }
 }
 
 class AzureSource {
   static authenticate(username: string, password: string): Promise<any> {
     return new Promise((resolve, reject) => {
-      AzureApiCaller.send({
+      Api.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)
+        let entries = Object.keys(response.data.tokenCache)[0]
+        let accessToken = response.data.tokenCache[entries][0].accessToken
+        Api.setDefaultHeader('Authorization', `Bearer ${accessToken}`)
+        resolve(response.data)
       }, reject)
     })
   }
 
   static getResourceGroups(subscriptionId: string): Promise<$PropertyType<Assessment, 'group'>[]> {
     return new Promise((resolve, reject) => {
-      AzureApiCaller.send({
-        url: resourceGroupsUrl({ subscriptionId }),
-      }, '2017-08-01').then(response => {
-        resolve(response.value)
+      Api.get(Util.buildUrl(resourceGroupsUrl({ subscriptionId }), '2017-08-01')).then(response => {
+        Util.responseIsValid(resolve, reject, response, response.data.value)
       }, reject)
     })
   }
@@ -84,10 +103,12 @@ class AzureSource {
       let groupsQueue = 0
 
       // Load projects
-      AzureApiCaller.send({
-        url: projectsUrl({ resourceGroupName, subscriptionId }),
-      }).then(response => {
-        let projects = response.value
+      Api.get(Util.buildUrl(projectsUrl({ resourceGroupName, subscriptionId }))).then(response => {
+        if (!Util.responseIsValid(resolve, reject, response)) {
+          return
+        }
+
+        let projects = response.data.value
         projectsQueue = projects.length
 
         if (projectsQueue === 0 && subscriptionId + resourceGroupName === this.reqId) {
@@ -99,12 +120,13 @@ class AzureSource {
             return
           }
           // Load Groups
-          AzureApiCaller.send({
-            url: groupsUrl({ projectName: project.name, subscriptionId, resourceGroupName }),
-          }).then(response => {
+          Api.get(Util.buildUrl(groupsUrl({ projectName: project.name, subscriptionId, resourceGroupName }))).then(response => {
+            if (!Util.responseIsValid(resolve, reject, response)) {
+              return
+            }
             projectsQueue -= 1
 
-            let groups = response.value
+            let groups = response.data.value
             groupsQueue = groups.length
 
             if (groupsQueue === 0 && subscriptionId + resourceGroupName === this.reqId) {
@@ -113,16 +135,17 @@ class AzureSource {
 
             groups.forEach(group => {
               // Load Assessments
-              AzureApiCaller.send({
-                url: assessmentsUrl({ subscriptionId, resourceGroupName, projectName: project.name, groupName: group.name }),
-              }).then(response => {
+              Api.get(Util.buildUrl(assessmentsUrl({ subscriptionId, resourceGroupName, projectName: project.name, groupName: group.name }))).then(response => {
+                if (!Util.responseIsValid(resolve, reject, response)) {
+                  return
+                }
                 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)) }) })
+                assessments = assessments.concat(response.data.value.map(a => ({ ...a, project, group })))
+                Util.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(Util.sortAssessments(assessments)) })
+              }, () => { groupsQueue -= 1; Util.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(Util.sortAssessments(assessments)) }) })
             })
-          }, () => { projectsQueue -= 1; AzureSourceUtil.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(AzureSourceUtil.sortAssessments(assessments)) }) })
+          }, () => { projectsQueue -= 1; Util.checkQueues([groupsQueue, projectsQueue], [subscriptionId + resourceGroupName, this.reqId], () => { resolve(Util.sortAssessments(assessments)) }) })
         })
       }, reject)
     })
@@ -130,21 +153,20 @@ class AzureSource {
 
   static getAssessmentDetails(info: Assessment): Promise<Assessment> {
     return new Promise((resolve, reject) => {
-      AzureApiCaller.send({
-        url: assessmentDetailsUrl({ ...info, subscriptionId: info.connectionInfo.subscription_id }),
-      }).then(response => {
-        let assessment = { ...response, ...info }
-        resolve(assessment)
+      Api.get(Util.buildUrl(assessmentDetailsUrl({ ...info, subscriptionId: info.connectionInfo.subscription_id }))).then(response => {
+        Util.responseIsValid(resolve, reject, response, { ...response.data, ...info })
       }, reject)
     })
   }
 
   static getAssessedVms(info: Assessment): Promise<VmItem[]> {
     return new Promise((resolve, reject) => {
-      AzureApiCaller.send({
-        url: assessedVmsUrl({ ...info, subscriptionId: info.connectionInfo.subscription_id }),
-      }).then(response => {
-        let vms = response.value
+      Api.get(Util.buildUrl(assessedVmsUrl({ ...info, subscriptionId: info.connectionInfo.subscription_id }))).then(response => {
+        if (!Util.responseIsValid(resolve, reject, response)) {
+          return
+        }
+
+        let vms = response.data.value
         vms.sort((a, b) => {
           let getLabel = item => `${item.properties.datacenterContainer}/${item.properties.displayName}`
           return getLabel(a).localeCompare(getLabel(b))
@@ -156,11 +178,8 @@ class AzureSource {
 
   static getVmSizes(info: Assessment): Promise<VmSize[]> {
     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)
+      Api.get(Util.buildUrl(`/subscriptions/${info.connectionInfo.subscription_id}/providers/Microsoft.Compute/locations/${info.location}/vmSizes`, '2017-12-01')).then(response => {
+        Util.responseIsValid(resolve, reject, response, response.data.value)
       }, reject)
     })
   }

+ 2 - 1
src/types/Assessment.js

@@ -46,6 +46,7 @@ export type Assessment = {
   projectName: string,
   resourceGroupName: string,
   groupName: string,
+  location: string,
   properties: {
     azureLocation: string,
   },
@@ -61,7 +62,7 @@ export type Assessment = {
     updatedTimestamp: string,
     azureLocation: string,
   },
-  connectionInfo: $PropertyType<Endpoint, 'connection_info'>,
+  connectionInfo: { subscription_id: string } & $PropertyType<Endpoint, 'connection_info'>,
 }
 
 export type MigrationInfo = {

+ 0 - 91
src/utils/AzureApiCaller.js

@@ -1,91 +0,0 @@
-/*
-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 <http://www.gnu.org/licenses/>.
-*/
-
-// @flow
-
-import request from 'ajax-request'
-
-let apiInstance = null
-let defaultApiVersion = '2017-11-11-preview'
-let azureUrl = 'https://management.azure.com/'
-
-type RequestOptions = {
-  headers?: {[string]: mixed},
-  url: string,
-}
-
-class AzureApiCaller {
-  headers: {[string]: mixed}
-
-  constructor() {
-    if (!apiInstance) {
-      apiInstance = this
-    }
-
-    this.headers = {}
-
-    return apiInstance
-  }
-
-  rejectError(error: string, reject: (error: any) => void) {
-    console.error('%c', 'color: #D0021B', error) // eslint-disable-line no-console
-    reject(error)
-  }
-
-  send(options: RequestOptions, apiVersion?: string): Promise<any> {
-    return new Promise((resolve, reject) => {
-      options.headers = {
-        ...options.headers,
-        ...this.headers,
-      }
-      let logUrl = options.url
-      console.log(`%cSending request to Azure proxy: ${logUrl}`, 'color: #F5A623') // eslint-disable-line no-console
-
-      if (options.url.indexOf('/azure-login') === -1) {
-        options.url = `/proxy/${`${azureUrl + options.url}?api-version=${apiVersion || defaultApiVersion}`}`
-      }
-
-      request(options, (err, resp, body) => {
-        if (!err && resp.statusCode === 200) {
-          let bodyJs
-
-          try {
-            bodyJs = JSON.parse(body)
-          } catch (ex) {
-            reject(ex)
-          }
-
-          if (!bodyJs) {
-            this.rejectError('Incorrect response body', reject)
-          } else if (bodyJs.error) {
-            this.rejectError(`${bodyJs.error.code}: ${bodyJs.error.message}`, reject)
-          } else {
-            console.log(`%cReceiving request from Azure proxy '${logUrl}':`, 'color: #0044CA', bodyJs) // eslint-disable-line no-console
-            resolve(bodyJs)
-          }
-        } else if (err) {
-          this.rejectError(`${err.code}: ${err.message}`, reject)
-        } else {
-          this.rejectError('Request failed, there might be a problem with the connection to the server.', reject)
-        }
-      })
-    })
-  }
-
-  setHeader(name: string, value: ?string) {
-    this.headers[name] = value
-  }
-}
-
-export default new AzureApiCaller()

+ 0 - 24
yarn.lock

@@ -271,13 +271,6 @@ airbnb-js-shims@^1.3.0:
     string.prototype.padend "^3.0.0"
     string.prototype.padstart "^3.0.0"
 
-ajax-request@^1.2.3:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/ajax-request/-/ajax-request-1.2.3.tgz#99fcbec1d6d2792f85fa949535332bd14f5f3790"
-  dependencies:
-    file-system "^2.1.1"
-    utils-extend "^1.0.7"
-
 ajv-keywords@^1.1.1:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
@@ -3309,19 +3302,6 @@ file-loader@^1.1.5:
     loader-utils "^1.0.2"
     schema-utils "^0.3.0"
 
-file-match@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/file-match/-/file-match-1.0.2.tgz#c9cad265d2c8adf3a81475b0df475859069faef7"
-  dependencies:
-    utils-extend "^1.0.6"
-
-file-system@^2.1.1:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/file-system/-/file-system-2.2.2.tgz#7d65833e3a2347dcd956a813c677153ed3edd987"
-  dependencies:
-    file-match "^1.0.1"
-    utils-extend "^1.0.4"
-
 filename-regex@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@@ -7579,10 +7559,6 @@ utila@~0.4:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
 
-utils-extend@^1.0.4, utils-extend@^1.0.6, utils-extend@^1.0.7:
-  version "1.0.8"
-  resolved "https://registry.yarnpkg.com/utils-extend/-/utils-extend-1.0.8.tgz#ccfd7b64540f8e90ee21eec57769d0651cab8a5f"
-
 utils-merge@1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"