ReplicaSource.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 Api from '../utils/ApiCaller'
  17. import { OptionsSchemaPlugin } from '../plugins/endpoint'
  18. import { servicesUrl } from '../constants'
  19. import type { MainItem, UpdateData } from '../types/MainItem'
  20. import type { Execution } from '../types/Execution'
  21. import type { Endpoint } from '../types/Endpoint'
  22. import type { Field } from '../types/Field'
  23. class ReplicaSourceUtils {
  24. static filterDeletedExecutionsInReplicas(replicas) {
  25. return replicas.map(replica => {
  26. replica.executions = ReplicaSourceUtils.filterDeletedExecutions(replica.executions)
  27. return replica
  28. })
  29. }
  30. static filterDeletedExecutions(executions) {
  31. if (!executions || !executions.length) {
  32. return executions
  33. }
  34. return executions.filter(execution => execution.deleted_at == null)
  35. }
  36. static sortReplicas(replicas) {
  37. if (replicas.length === 1) {
  38. ReplicaSourceUtils.sortExecutions(replicas[0].executions)
  39. return
  40. }
  41. replicas.sort((a, b) => {
  42. ReplicaSourceUtils.sortExecutions(a.executions)
  43. ReplicaSourceUtils.sortExecutions(b.executions)
  44. let aLastExecution = a.executions && a.executions.length ? a.executions[a.executions.length - 1] : null
  45. let bLastExecution = b.executions && b.executions.length ? b.executions[b.executions.length - 1] : null
  46. let aLastTime = aLastExecution ? aLastExecution.updated_at || aLastExecution.created_at : null
  47. let bLastTime = bLastExecution ? bLastExecution.updated_at || bLastExecution.created_at : null
  48. let aTime = aLastTime || a.updated_at || a.created_at
  49. let bTime = bLastTime || b.updated_at || b.created_at
  50. return moment(bTime).diff(moment(aTime))
  51. })
  52. }
  53. static sortExecutions(executions) {
  54. if (executions) {
  55. executions.sort((a, b) => a.number - b.number)
  56. }
  57. }
  58. static sortExecutionsAndTaskUpdates(executions) {
  59. this.sortExecutions(executions)
  60. executions.forEach(execution => {
  61. this.sortTaskUpdates(execution)
  62. })
  63. }
  64. static sortTaskUpdates(execution) {
  65. if (execution.tasks) {
  66. execution.tasks.forEach(task => {
  67. if (task.progress_updates) {
  68. task.progress_updates.sort((a, b) => moment(a.created_at).toDate().getTime() - moment(b.created_at).toDate().getTime())
  69. }
  70. })
  71. }
  72. }
  73. }
  74. class ReplicaSource {
  75. static getReplicas(): Promise<MainItem[]> {
  76. return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/replicas/detail`).then(response => {
  77. let replicas = response.data.replicas
  78. replicas = ReplicaSourceUtils.filterDeletedExecutionsInReplicas(replicas)
  79. ReplicaSourceUtils.sortReplicas(replicas)
  80. return replicas
  81. })
  82. }
  83. static getReplicaExecutions(replicaId: string): Promise<Execution[]> {
  84. return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/detail`).then((response) => {
  85. let executions = response.data.executions
  86. ReplicaSourceUtils.sortExecutionsAndTaskUpdates(executions)
  87. return executions
  88. })
  89. }
  90. static getReplica(replicaId: string): Promise<MainItem> {
  91. return Api.get(`${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}`).then(response => {
  92. let replica = response.data.replica
  93. replica.executions = ReplicaSourceUtils.filterDeletedExecutions(replica.executions)
  94. ReplicaSourceUtils.sortExecutions(replica.executions)
  95. return replica
  96. })
  97. }
  98. static execute(replicaId: string, fields?: Field[]): Promise<Execution> {
  99. let payload = { execution: { shutdown_instances: false } }
  100. if (fields) {
  101. fields.forEach(f => {
  102. payload.execution[f.name] = f.value || false
  103. })
  104. }
  105. return Api.send({
  106. url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions`,
  107. method: 'POST',
  108. data: payload,
  109. }).then((response) => {
  110. let execution = response.data.execution
  111. ReplicaSourceUtils.sortTaskUpdates(execution)
  112. return execution
  113. })
  114. }
  115. static cancelExecution(replicaId: string, executionId: string): Promise<string> {
  116. return Api.send({
  117. url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/${executionId}/actions`,
  118. method: 'POST',
  119. data: { cancel: null },
  120. }).then(() => replicaId)
  121. }
  122. static deleteExecution(replicaId: string, executionId: string): Promise<string> {
  123. return Api.send({
  124. url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/executions/${executionId}`,
  125. method: 'DELETE',
  126. }).then(() => replicaId)
  127. }
  128. static delete(replicaId: string): Promise<string> {
  129. return Api.send({
  130. url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}`,
  131. method: 'DELETE',
  132. }).then(() => replicaId)
  133. }
  134. static deleteDisks(replicaId: string): Promise<Execution> {
  135. return Api.send({
  136. url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replicaId}/actions`,
  137. method: 'POST',
  138. data: { 'delete-disks': null },
  139. }).then(response => response.data.execution)
  140. }
  141. static update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, storageConfigDefault: string): Promise<Execution> {
  142. const parser = OptionsSchemaPlugin[destinationEndpoint.type] || OptionsSchemaPlugin.default
  143. let payload = { replica: {} }
  144. if (updateData.network.length > 0) {
  145. let networkMap = {}
  146. updateData.network.forEach(mapping => {
  147. networkMap[mapping.sourceNic.network_name] = mapping.targetNetwork.id
  148. })
  149. payload.replica.network_map = networkMap
  150. }
  151. if (Object.keys(updateData.destination).length > 0) {
  152. payload.replica.destination_environment = parser.getDestinationEnv(updateData.destination, replica.destination_environment)
  153. }
  154. if (Object.keys(updateData.source).length > 0) {
  155. payload.replica.source_environment = parser.getDestinationEnv(updateData.source, replica.source_environment)
  156. }
  157. let defaultStorage = updateData.destination && updateData.destination.default_storage
  158. if (defaultStorage || updateData.storage.length > 0) {
  159. payload.replica.storage_mappings = parser.getStorageMap(defaultStorage, updateData.storage, storageConfigDefault)
  160. }
  161. return Api.send({
  162. url: `${servicesUrl.coriolis}/${Api.projectId}/replicas/${replica.id}`,
  163. method: 'PUT',
  164. data: payload,
  165. }).then(response => response.data)
  166. }
  167. }
  168. export default ReplicaSource