MinionPoolStore.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 { action, observable, runInAction, computed } from "mobx";
  15. import { MinionPool, MinionPoolDetails } from "@src/@types/MinionPool";
  16. import MinionPoolSource from "@src/sources/MinionPoolSource";
  17. import { Field, isEnumSeparator } from "@src/@types/Field";
  18. import { Providers, ProviderTypes } from "@src/@types/Providers";
  19. import { OptionsSchemaPlugin } from "@src/plugins";
  20. import { providerTypes } from "@src/constants";
  21. import apiCaller from "@src/utils/ApiCaller";
  22. import { Endpoint, OptionValues } from "@src/@types/Endpoint";
  23. export type MinionPoolAction = "allocate" | "deallocate" | "refresh";
  24. export const MinionPoolStoreUtils = {
  25. isActive: (minionPool: MinionPool) =>
  26. minionPool.status === "ALLOCATED" ||
  27. minionPool.status === "SCALING" ||
  28. minionPool.status === "RESCALING",
  29. };
  30. class MinionPoolStore {
  31. @observable
  32. loadingMinionPools = false;
  33. @observable
  34. minionPools: MinionPool[] = [];
  35. @observable
  36. loadingMinionPoolDetails = false;
  37. @observable
  38. minionPoolDetails: MinionPoolDetails | null = null;
  39. @observable
  40. loadingMinionPoolSchema = false;
  41. @observable
  42. minionPoolDefaultSchema: Field[] = [];
  43. @observable
  44. minionPoolEnvSchema: Field[] = [];
  45. @observable
  46. optionsPrimaryLoading = false;
  47. @observable
  48. optionsSecondaryLoading = false;
  49. @computed
  50. get minionPoolCombinedSchema() {
  51. return this.minionPoolDefaultSchema.concat(this.minionPoolEnvSchema);
  52. }
  53. @action
  54. async loadMinionPools(options?: {
  55. showLoading?: boolean;
  56. skipLog?: boolean;
  57. }) {
  58. if (options?.showLoading) {
  59. this.loadingMinionPools = true;
  60. }
  61. try {
  62. const minionPools = await MinionPoolSource.loadMinionPools({
  63. skipLog: options?.skipLog,
  64. });
  65. runInAction(() => {
  66. this.minionPools = minionPools;
  67. });
  68. } finally {
  69. runInAction(() => {
  70. this.loadingMinionPools = false;
  71. });
  72. }
  73. }
  74. @action
  75. async loadMinionPoolDetails(
  76. id: string,
  77. options?: { showLoading?: boolean; skipLog?: boolean }
  78. ) {
  79. if (options?.showLoading) {
  80. this.loadingMinionPoolDetails = true;
  81. }
  82. try {
  83. const minionPool = await MinionPoolSource.loadMinionPoolDetails(id, {
  84. skipLog: options?.skipLog,
  85. });
  86. runInAction(() => {
  87. this.minionPoolDetails = minionPool;
  88. });
  89. } finally {
  90. runInAction(() => {
  91. this.loadingMinionPoolDetails = false;
  92. });
  93. }
  94. }
  95. @action clearMinionPoolDetails() {
  96. this.minionPoolDetails = null;
  97. }
  98. @action
  99. async loadMinionPoolSchema(
  100. provider: ProviderTypes,
  101. platform: "source" | "destination"
  102. ) {
  103. this.loadingMinionPoolSchema = true;
  104. this.minionPoolDefaultSchema =
  105. MinionPoolSource.getMinionPoolDefaultSchema();
  106. try {
  107. const schema = await MinionPoolSource.loadMinionPoolSchema(
  108. provider,
  109. platform
  110. );
  111. runInAction(() => {
  112. this.minionPoolEnvSchema = schema;
  113. });
  114. } finally {
  115. runInAction(() => {
  116. this.loadingMinionPoolSchema = false;
  117. });
  118. }
  119. }
  120. private getOptionsValuesLastReqId = "";
  121. async loadOptions(config: {
  122. endpoint: Endpoint;
  123. providers: Providers;
  124. optionsType: "source" | "destination";
  125. envData?: { [prop: string]: any } | null;
  126. useCache?: boolean;
  127. }) {
  128. const { optionsType, endpoint, envData, useCache, providers } = config;
  129. const providerType =
  130. optionsType === "source"
  131. ? providerTypes.SOURCE_OPTIONS
  132. : providerTypes.DESTINATION_OPTIONS;
  133. const providerWithExtraOptions = providers[endpoint.type].types.find(
  134. t => t === providerType
  135. );
  136. if (!providerWithExtraOptions) {
  137. return;
  138. }
  139. let canceled = false;
  140. apiCaller.cancelRequests(endpoint.id);
  141. this.optionsPrimaryLoading = !envData;
  142. this.optionsSecondaryLoading = !!envData;
  143. const reqId = `${endpoint.id}-${providerType}`;
  144. this.getOptionsValuesLastReqId = reqId;
  145. try {
  146. const options = await MinionPoolSource.loadOptions({
  147. optionsType,
  148. endpoint,
  149. envData,
  150. useCache,
  151. });
  152. this.getOptionsValuesSuccess(
  153. endpoint.type,
  154. options,
  155. this.getOptionsValuesLastReqId === reqId
  156. );
  157. } catch (err) {
  158. canceled = err ? err.canceled : false;
  159. throw err;
  160. } finally {
  161. if (!canceled && this.getOptionsValuesLastReqId === reqId) {
  162. this.optionsPrimaryLoading = false;
  163. this.optionsSecondaryLoading = false;
  164. }
  165. }
  166. }
  167. @action getOptionsValuesSuccess(
  168. provider: ProviderTypes,
  169. options: OptionValues[],
  170. isValid: boolean
  171. ) {
  172. if (!isValid) {
  173. return;
  174. }
  175. this.minionPoolEnvSchema.forEach(field => {
  176. const parser = OptionsSchemaPlugin.for(provider);
  177. parser.fillFieldValues({ field, options, requiresWindowsImage: false });
  178. });
  179. this.minionPoolEnvSchema = [...this.minionPoolEnvSchema];
  180. }
  181. @action
  182. async update(provider: ProviderTypes, minionPoolData: any) {
  183. return MinionPoolSource.update({
  184. data: minionPoolData,
  185. defaultSchema: this.minionPoolDefaultSchema,
  186. envSchema: this.minionPoolEnvSchema,
  187. provider,
  188. });
  189. }
  190. @action
  191. async add(provider: ProviderTypes, endpointId: string, minionPoolData: any) {
  192. return MinionPoolSource.add({
  193. endpointId,
  194. data: minionPoolData,
  195. defaultSchema: this.minionPoolDefaultSchema,
  196. envSchema: this.minionPoolEnvSchema,
  197. provider,
  198. });
  199. }
  200. @action
  201. async runAction(
  202. minionPoolId: string,
  203. minionPoolAction: MinionPoolAction,
  204. actionOptions?: any
  205. ) {
  206. return MinionPoolSource.runAction(
  207. minionPoolId,
  208. minionPoolAction,
  209. actionOptions
  210. );
  211. }
  212. async deleteMinionPool(minionPoolId: string) {
  213. return MinionPoolSource.deleteMinionPool(minionPoolId);
  214. }
  215. @action
  216. sortMigrImages(osType: "linux" | "windows") {
  217. const migrImageField = this.minionPoolEnvSchema.find(
  218. field => field.name === "migr_image"
  219. );
  220. if (!migrImageField || !migrImageField.enum) {
  221. return;
  222. }
  223. migrImageField.enum = migrImageField.enum
  224. .slice()
  225. .filter(f => !isEnumSeparator(f))
  226. .sort((a, b) => {
  227. const anyA = a as any;
  228. const anyB = b as any;
  229. if (anyA.os_type === osType && anyB.os_type !== osType) {
  230. return -1;
  231. } else if (anyB.os_type === osType && anyA.os_type !== osType) {
  232. return 1;
  233. } else {
  234. return 0;
  235. }
  236. });
  237. const osIndex = migrImageField.enum.findIndex(
  238. server => (server as any).os_type !== osType
  239. );
  240. if (osIndex > -1) {
  241. migrImageField.enum.splice(osIndex, 0, { separator: true });
  242. }
  243. this.minionPoolEnvSchema = [...this.minionPoolEnvSchema];
  244. }
  245. }
  246. export default new MinionPoolStore();