MigrationSource.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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 { OptionsSchemaPlugin } from '../plugins/endpoint'
  17. import Api from '../utils/ApiCaller'
  18. import type { MainItem } from '../types/MainItem'
  19. import type { Field } from '../types/Field'
  20. import type { NetworkMap } from '../types/Network'
  21. import type { Endpoint, StorageMap } from '../types/Endpoint'
  22. import { servicesUrl } from '../constants'
  23. class MigrationSourceUtils {
  24. static sortTaskUpdates(migration) {
  25. if (migration && migration.tasks) {
  26. migration.tasks.forEach(task => {
  27. if (task && task.progress_updates) {
  28. task.progress_updates.sort((a, b) => {
  29. let sortNull = !a && b ? 1 : a && !b ? -1 : !a && !b ? 0 : false
  30. if (sortNull !== false) {
  31. return sortNull
  32. }
  33. return moment(a.created_at).toDate().getTime() - moment(b.created_at).toDate().getTime()
  34. })
  35. }
  36. })
  37. }
  38. }
  39. static sortMigrations(migrations) {
  40. migrations.sort((a, b) => moment(b.created_at).diff(moment(a.created_at)))
  41. migrations.forEach(migration => {
  42. MigrationSourceUtils.sortTaskUpdates(migration)
  43. })
  44. }
  45. }
  46. class MigrationSource {
  47. static getMigrations(): Promise<MainItem[]> {
  48. return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/migrations/detail`).then(response => {
  49. let migrations = response.data.migrations
  50. MigrationSourceUtils.sortMigrations(migrations)
  51. return migrations
  52. })
  53. }
  54. static getMigration(migrationId: string): Promise<MainItem> {
  55. return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}`).then(response => {
  56. let migration = response.data.migration
  57. MigrationSourceUtils.sortTaskUpdates(migration)
  58. return migration
  59. })
  60. }
  61. static recreate(opts: {
  62. sourceEndpoint: Endpoint,
  63. destEndpoint: Endpoint,
  64. instanceNames: string[],
  65. destEnv: ?{ [string]: any },
  66. updatedDestEnv: ?{ [string]: any },
  67. sourceEnv?: ?{ [string]: any },
  68. updatedSourceEnv?: ?{ [string]: any },
  69. storageMappings: ?{ [string]: any },
  70. updatedStorageMappings: ?StorageMap[],
  71. networkMappings: ?{ [string]: any },
  72. updatedNetworkMappings: ?NetworkMap[],
  73. }): Promise<MainItem> {
  74. const getValue = (fieldName: string): ?string => {
  75. return (opts.updatedDestEnv && opts.updatedDestEnv[fieldName]) ||
  76. (opts.destEnv && opts.destEnv[fieldName])
  77. }
  78. const sourceParser = OptionsSchemaPlugin[opts.sourceEndpoint.type] || OptionsSchemaPlugin.default
  79. const destParser = OptionsSchemaPlugin[opts.destEndpoint.type] || OptionsSchemaPlugin.default
  80. let payload: any = {}
  81. payload.migration = {
  82. origin_endpoint_id: opts.sourceEndpoint.id,
  83. destination_endpoint_id: opts.destEndpoint.id,
  84. destination_environment: {
  85. ...opts.destEnv,
  86. ...destParser.getDestinationEnv(opts.updatedDestEnv),
  87. },
  88. instances: opts.instanceNames,
  89. notes: getValue('description') || '',
  90. }
  91. if (getValue('skip_os_morphing') != null) {
  92. payload.migration.skip_os_morphing = getValue('skip_os_morphing')
  93. }
  94. if (opts.networkMappings || (opts.updatedNetworkMappings && opts.updatedNetworkMappings.length)) {
  95. payload.migration.network_map = {
  96. ...opts.networkMappings,
  97. ...destParser.getNetworkMap(opts.updatedNetworkMappings),
  98. }
  99. }
  100. if ((opts.storageMappings && Object.keys(opts.storageMappings).length)
  101. || (opts.updatedStorageMappings && opts.updatedStorageMappings.length)) {
  102. payload.migration.storage_mappings = {
  103. ...opts.storageMappings,
  104. ...destParser.getStorageMap(getValue('default_storage'), opts.updatedStorageMappings),
  105. }
  106. }
  107. if (opts.sourceEnv || opts.updatedSourceEnv) {
  108. payload.migration.source_environment = {
  109. ...opts.sourceEnv,
  110. ...sourceParser.getDestinationEnv(opts.updatedSourceEnv),
  111. }
  112. }
  113. return Api.send({
  114. url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`,
  115. method: 'POST',
  116. data: payload,
  117. }).then(response => response.data.migration)
  118. }
  119. static cancel(migrationId: string): Promise<string> {
  120. return Api.send({
  121. url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}/actions`,
  122. method: 'POST',
  123. data: { cancel: null },
  124. }).then(() => migrationId)
  125. }
  126. static delete(migrationId: string): Promise<string> {
  127. return Api.send({
  128. url: `${servicesUrl.coriolis}/${Api.projectId}/migrations/${migrationId}`,
  129. method: 'DELETE',
  130. }).then(() => migrationId)
  131. }
  132. static migrateReplica(replicaId: string, options: Field[]): Promise<MainItem> {
  133. let payload = {
  134. migration: {
  135. replica_id: replicaId,
  136. },
  137. }
  138. options.forEach(o => {
  139. payload.migration[o.name] = o.value || false
  140. })
  141. return Api.send({
  142. url: `${servicesUrl.coriolis}/${Api.projectId}/migrations`,
  143. method: 'POST',
  144. data: payload,
  145. }).then(response => response.data.migration)
  146. }
  147. }
  148. export default MigrationSource