OptionsSchemaPlugin.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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 { defaultSchemaToFields } from './ConnectionSchemaPlugin'
  16. import Utils from '../../../utils/ObjectUtils'
  17. import type { Field } from '../../../types/Field'
  18. import type { OptionValues, StorageMap } from '../../../types/Endpoint'
  19. import type { SchemaProperties, SchemaDefinitions } from '../../../types/Schema'
  20. import type { NetworkMap } from '../../../types/Network'
  21. import type { InstanceScript } from '../../../types/Instance'
  22. import { executionOptions, migrationFields } from '../../../constants'
  23. const migrationImageOsTypes = ['windows', 'linux']
  24. export const defaultFillFieldValues = (field: Field, option: OptionValues) => {
  25. if (field.type === 'string') {
  26. field.enum = [...option.values]
  27. if (option.config_default) {
  28. field.default = typeof option.config_default === 'string' ? option.config_default : option.config_default.id
  29. }
  30. }
  31. if (field.type === 'array') {
  32. field.enum = [...option.values]
  33. }
  34. if (field.type === 'boolean' && option.config_default != null) {
  35. field.default = typeof option.config_default === 'boolean' ? option.config_default : option.config_default === 'true'
  36. }
  37. }
  38. export const defaultFillMigrationImageMapValues = (field: Field, option: OptionValues): boolean => {
  39. if (field.name !== 'migr_image_map') {
  40. return false
  41. }
  42. field.properties = migrationImageOsTypes.map(os => {
  43. let values = option.values
  44. .filter(v => v.os_type === os || v.os_type === 'unknown')
  45. .sort((v1, v2) => {
  46. if (v1.os_type === 'unknown' && v2.os_type !== 'unknown') {
  47. return 1
  48. } else if (v1.os_type !== 'unknown' && v2.os_type === 'unknown') {
  49. return -1
  50. }
  51. return 0
  52. })
  53. let unknownIndex = values.findIndex(v => v.os_type === 'unknown')
  54. if (unknownIndex > -1 && values.filter(v => v.os_type === 'unknown').length < values.length) {
  55. values.splice(unknownIndex, 0, { separator: true })
  56. }
  57. return {
  58. name: `${os}_os_image`,
  59. type: 'string',
  60. enum: values,
  61. }
  62. })
  63. return true
  64. }
  65. export const defaultGetDestinationEnv = (options: ?{ [string]: mixed }, oldOptions?: ?{ [string]: mixed }): any => {
  66. let env = {}
  67. let specialOptions = ['execute_now', 'separate_vm', 'skip_os_morphing', 'description']
  68. .concat(migrationFields.map(f => f.name))
  69. .concat(executionOptions.map(o => o.name))
  70. .concat(migrationImageOsTypes.map(o => `${o}_os_image`))
  71. if (!options) {
  72. return env
  73. }
  74. Object.keys(options).forEach(optionName => {
  75. if (specialOptions.find(o => o === optionName) || !options || options[optionName] == null || options[optionName] === '') {
  76. return
  77. }
  78. if (optionName.indexOf('/') > 0) {
  79. let parentName = optionName.substr(0, optionName.lastIndexOf('/'))
  80. if (!env[parentName]) {
  81. env[parentName] = oldOptions ? oldOptions[parentName] || {} : {}
  82. }
  83. env[parentName][optionName.substr(optionName.lastIndexOf('/') + 1)] = options
  84. ? Utils.trim(optionName, options[optionName]) : null
  85. } else {
  86. env[optionName] = options ? Utils.trim(optionName, options[optionName]) : null
  87. }
  88. })
  89. return env
  90. }
  91. export const defaultGetMigrationImageMap = (options: ?{ [string]: mixed }) => {
  92. let env = {}
  93. if (!options) {
  94. return env
  95. }
  96. migrationImageOsTypes.forEach(os => {
  97. if (!options || !options[`${os}_os_image`]) {
  98. return
  99. }
  100. if (!env.migr_image_map) {
  101. env.migr_image_map = {}
  102. }
  103. env.migr_image_map[os] = options[`${os}_os_image`]
  104. })
  105. return env
  106. }
  107. export default class OptionsSchemaParser {
  108. static parseSchemaToFields(schema: SchemaProperties, schemaDefinitions?: ?SchemaDefinitions) {
  109. return defaultSchemaToFields(schema, schemaDefinitions)
  110. }
  111. static fillFieldValues(field: Field, options: OptionValues[], customFieldName?: string) {
  112. let option = options.find(f => customFieldName ? f.name === customFieldName : f.name === field.name)
  113. if (!option) {
  114. return
  115. }
  116. if (!defaultFillMigrationImageMapValues(field, option)) {
  117. defaultFillFieldValues(field, option)
  118. }
  119. }
  120. static getDestinationEnv(options: ?{ [string]: mixed }, oldOptions?: any) {
  121. let env = {
  122. ...defaultGetDestinationEnv(options, oldOptions),
  123. ...defaultGetMigrationImageMap(options),
  124. }
  125. return env
  126. }
  127. static getNetworkMap(networkMappings: ?NetworkMap[]) {
  128. let payload = {}
  129. if (networkMappings && networkMappings.length) {
  130. let hasSecurityGroups = Boolean(networkMappings.find(nm => nm.targetNetwork.security_groups))
  131. networkMappings.forEach(mapping => {
  132. let target
  133. if (hasSecurityGroups) {
  134. target = {
  135. id: mapping.targetNetwork.id,
  136. security_groups: mapping.targetSecurityGroups ? mapping.targetSecurityGroups.map(s => s.id ? s.id : s) : [],
  137. }
  138. } else {
  139. target = mapping.targetNetwork.id
  140. }
  141. payload[mapping.sourceNic.network_name] = target
  142. })
  143. }
  144. return payload
  145. }
  146. static getStorageMap(defaultStorage: ?string, storageMap: ?StorageMap[], configDefault?: ?string) {
  147. if (!defaultStorage && !storageMap) {
  148. return null
  149. }
  150. let payload = {}
  151. if (defaultStorage) {
  152. payload.default = defaultStorage
  153. }
  154. if (!storageMap) {
  155. return payload
  156. }
  157. storageMap.forEach(mapping => {
  158. if (mapping.target.id === null && !configDefault) {
  159. return
  160. }
  161. if (mapping.type === 'backend') {
  162. if (!payload.backend_mappings) {
  163. payload.backend_mappings = []
  164. }
  165. payload.backend_mappings.push({
  166. source: mapping.source.storage_backend_identifier,
  167. destination: mapping.target.id === null ? configDefault : mapping.target.name,
  168. })
  169. } else {
  170. if (!payload.disk_mappings) {
  171. payload.disk_mappings = []
  172. }
  173. payload.disk_mappings.push({
  174. disk_id: mapping.source.id.toString(),
  175. destination: mapping.target.id === null ? configDefault : mapping.target.name,
  176. })
  177. }
  178. })
  179. return payload
  180. }
  181. static getUserScripts(uploadedUserScripts: InstanceScript[]) {
  182. let payload = {}
  183. let globalScripts = uploadedUserScripts.filter(s => s.global)
  184. if (globalScripts.length) {
  185. payload.global = {}
  186. globalScripts.forEach(script => {
  187. payload.global[script.global || ''] = script.scriptContent
  188. })
  189. }
  190. let instanceScripts = uploadedUserScripts.filter(s => s.instanceName)
  191. if (instanceScripts.length) {
  192. payload.instances = {}
  193. instanceScripts.forEach(script => {
  194. payload.instances[script.instanceName || ''] = script.scriptContent
  195. })
  196. }
  197. return payload
  198. }
  199. }