MinionPoolSource.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. Copyright (C) 2020 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. import moment from 'moment'
  15. import Api from '../utils/ApiCaller'
  16. import configLoader from '../utils/Config'
  17. import { MinionPool, MinionPoolDetails } from '../@types/MinionPool'
  18. import { ProviderTypes } from '../@types/Providers'
  19. import { Field } from '../@types/Field'
  20. import { providerTypes } from '../constants'
  21. import { SchemaParser } from './Schemas'
  22. import { OptionValues } from '../@types/Endpoint'
  23. import { MinionPoolAction } from '../stores/MinionPoolStore'
  24. import { Execution, ExecutionTasks } from '../@types/Execution'
  25. import { sortTasks } from './ReplicaSource'
  26. import { ProgressUpdate } from '../@types/Task'
  27. const transformFieldsToPayload = (schema: Field[], data: any) => {
  28. const payload: any = {}
  29. schema.forEach(field => {
  30. if (data[field.name] === null || data[field.name] === undefined || data[field.name] === '') {
  31. if (field.default !== null) {
  32. payload[field.name] = field.default
  33. }
  34. } else {
  35. payload[field.name] = data[field.name]
  36. }
  37. })
  38. return payload
  39. }
  40. class MinionPoolSource {
  41. getMinionPoolDefaultSchema(): Field[] {
  42. return [
  43. {
  44. name: 'endpoint_id',
  45. label: 'Endpoint',
  46. type: 'string',
  47. },
  48. {
  49. name: 'pool_platform',
  50. type: 'string',
  51. },
  52. {
  53. name: 'pool_name',
  54. type: 'string',
  55. required: true,
  56. },
  57. {
  58. name: 'pool_os_type',
  59. type: 'string',
  60. required: true,
  61. enum: [
  62. {
  63. value: 'linux',
  64. label: 'Linux',
  65. },
  66. {
  67. value: 'windows',
  68. label: 'Windows',
  69. },
  70. ],
  71. },
  72. {
  73. name: 'minimum_minions',
  74. type: 'integer',
  75. minimum: 1,
  76. default: 1,
  77. },
  78. {
  79. name: 'notes',
  80. type: 'string',
  81. },
  82. ]
  83. }
  84. async loadMinionPools(options?: { skipLog?: boolean }): Promise<MinionPool[]> {
  85. const response = await Api.send({
  86. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/minion_pools`,
  87. skipLog: options?.skipLog,
  88. })
  89. return response.data.minion_pools
  90. }
  91. async loadEnvOptions(endpointId: string, platform: 'source' | 'destination', useCache?: boolean): Promise<OptionValues[]> {
  92. const response = await Api.send({
  93. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/endpoints/${endpointId}/${platform}-minion-pool-options`,
  94. cache: useCache,
  95. })
  96. return response.data[`${platform}_minion_pool_options`]
  97. }
  98. async loadMinionPoolSchema(providerName: ProviderTypes, platform: 'source' | 'destination'): Promise<Field[]> {
  99. const providerType = platform === 'source' ? providerTypes.SOURCE_MINION_POOL : providerTypes.DESTINATION_MINION_POOL
  100. try {
  101. const response = await Api.send({
  102. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/providers/${providerName}/schemas/${providerType}`,
  103. })
  104. const schema = response.data?.schemas?.[`${platform}_minion_pool_environment_schema`]
  105. let fields = []
  106. if (schema) {
  107. fields = SchemaParser.optionsSchemaToFields(providerName, schema, `${providerName}-minion-pool`)
  108. }
  109. return fields
  110. } catch (err) {
  111. console.error(err)
  112. return []
  113. }
  114. }
  115. async add(endpointId: string, data: any, defaultSchema: Field[], envSchema: Field[]) {
  116. const payload = {
  117. minion_pool: {
  118. ...transformFieldsToPayload(defaultSchema, data),
  119. endpoint_id: endpointId,
  120. environment_options: {
  121. ...transformFieldsToPayload(envSchema, data),
  122. },
  123. },
  124. }
  125. const response = await Api.send({
  126. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/minion_pools`,
  127. method: 'POST',
  128. data: payload,
  129. })
  130. return response.data.minion_pool
  131. }
  132. async update(data: any, defaultSchema: Field[], envSchema: Field[]) {
  133. const payload = {
  134. minion_pool: {
  135. ...transformFieldsToPayload(defaultSchema, data),
  136. environment_options: {
  137. ...transformFieldsToPayload(envSchema, data),
  138. },
  139. },
  140. }
  141. const response = await Api.send({
  142. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/minion_pools/${data.id}`,
  143. method: 'PUT',
  144. data: payload,
  145. })
  146. return response.data.minion_pool
  147. }
  148. async runAction(minionPoolId: string, minionPoolAction: MinionPoolAction): Promise<Execution> {
  149. const payload: any = {}
  150. payload[minionPoolAction] = null
  151. const response = await Api.send({
  152. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/minion_pools/${minionPoolId}/actions`,
  153. method: 'POST',
  154. data: payload,
  155. })
  156. return response.data.execution
  157. }
  158. async getMinionPoolDetails(
  159. minionPoolId: string,
  160. options?: { skipLog?: boolean },
  161. ): Promise<MinionPoolDetails> {
  162. const response = await Api.send({
  163. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/minion_pools/${minionPoolId}`,
  164. skipLog: options?.skipLog,
  165. })
  166. const minionPool: MinionPoolDetails = response.data.minion_pool
  167. minionPool.executions.sort((a, b) => a.number - b.number)
  168. return minionPool
  169. }
  170. async cancelExecution(minionPoolId: string, force?: boolean, executionId?: string) {
  171. let usableExecutionId = executionId
  172. if (!usableExecutionId) {
  173. const details = await this.getMinionPoolDetails(minionPoolId)
  174. const lastExecution = details.executions[details.executions.length - 1]
  175. if (!lastExecution) {
  176. return null
  177. }
  178. usableExecutionId = lastExecution.id
  179. }
  180. const payload: any = { cancel: { force: force || false } }
  181. await Api.send({
  182. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/minion_pools/${minionPoolId}/executions/${usableExecutionId}/actions`,
  183. method: 'POST',
  184. data: payload,
  185. })
  186. return null
  187. }
  188. async deleteMinionPool(minionPoolId: string) {
  189. const response = await Api.send({
  190. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/minion_pools/${minionPoolId}`,
  191. method: 'DELETE',
  192. })
  193. return response.data.execution
  194. }
  195. async getExecutionTasks(options: {
  196. minionPoolId: string,
  197. executionId?: string,
  198. skipLog?: boolean,
  199. }): Promise<ExecutionTasks> {
  200. const {
  201. minionPoolId, executionId, skipLog,
  202. } = options
  203. const response = await Api.send({
  204. url: `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/minion_pools/${minionPoolId}/executions/${executionId}`,
  205. skipLog,
  206. quietError: true,
  207. })
  208. const execution: ExecutionTasks = response.data.execution
  209. const sortTaskUpdates = (updates: ProgressUpdate[]) => {
  210. if (!updates) {
  211. return
  212. }
  213. updates.sort((a, b) => moment(a.created_at)
  214. .toDate().getTime() - moment(b.created_at).toDate().getTime())
  215. }
  216. sortTasks(execution.tasks, sortTaskUpdates)
  217. return execution
  218. }
  219. }
  220. export default new MinionPoolSource()