Explorar el Código

Merge pull request #503 from smiclea/default-storage

Move default storage from options to storage
Nashwan Azhari hace 6 años
padre
commit
8b618d1445

+ 17 - 5
src/components/organisms/EditReplica/EditReplica.jsx

@@ -99,6 +99,7 @@ type State = {
   sourceData: any,
   updateDisabled: boolean,
   selectedNetworks: NetworkMap[],
+  defaultStorage: ?string,
   storageMap: StorageMap[],
   sourceFailed: boolean,
   destinationFailedMessage: ?string,
@@ -112,6 +113,7 @@ class EditReplica extends React.Component<Props, State> {
     sourceData: {},
     updateDisabled: false,
     selectedNetworks: [],
+    defaultStorage: undefined,
     storageMap: [],
     sourceFailed: false,
     destinationFailedMessage: null,
@@ -311,9 +313,8 @@ class EditReplica extends React.Component<Props, State> {
       storage: this.state.storageMap,
     }
     if (this.props.type === 'replica') {
-      let storageConfigDefault = this.getFieldValue('destination', 'default_storage') || endpointStore.storageConfigDefault
       try {
-        await replicaStore.update(this.props.replica, this.props.destinationEndpoint, updateData, storageConfigDefault)
+        await replicaStore.update(this.props.replica, this.props.destinationEndpoint, updateData, this.getDefaultStorage(), endpointStore.storageConfigDefault)
         this.props.onRequestClose()
         this.props.onUpdateComplete(`/replica/executions/${this.props.replica.id}`)
       } catch (err) {
@@ -321,7 +322,8 @@ class EditReplica extends React.Component<Props, State> {
       }
     } else {
       try {
-        let migration: MainItem = await migrationStore.recreate(this.props.replica, this.props.sourceEndpoint, this.props.destinationEndpoint, updateData)
+        let replicaDefaultStorage = this.props.replica.storage_mappings && this.props.replica.storage_mappings.default
+        let migration: MainItem = await migrationStore.recreate(this.props.replica, this.props.sourceEndpoint, this.props.destinationEndpoint, updateData, replicaDefaultStorage, this.state.defaultStorage)
         migrationStore.clearDetails()
         this.props.onRequestClose()
         this.props.onUpdateComplete(`/migration/tasks/${migration.id}`)
@@ -347,6 +349,12 @@ class EditReplica extends React.Component<Props, State> {
     this.setState({ storageMap })
   }
 
+  getDefaultStorage() {
+    let storageMappings = this.props.replica.storage_mappings
+    let replicaDefaultStorage = storageMappings && storageMappings.default
+    return this.state.defaultStorage !== undefined ? this.state.defaultStorage : replicaDefaultStorage
+  }
+
   getFieldValue(type: 'source' | 'destination', fieldName: string, defaultValue: any) {
     let currentData = type === 'source' ? this.state.sourceData : this.state.destinationData
     if (currentData[fieldName] !== undefined) {
@@ -487,8 +495,8 @@ class EditReplica extends React.Component<Props, State> {
         layout="modal"
         isSource={type === 'source'}
         optionsLoading={optionsLoading}
-        optionsLoadingSkipFields={[...optionsLoadingSkipFields, 'description', 'execute_now', 'execute_now_options',
-          'default_storage', ...migrationFields.map(f => f.name)]}
+        optionsLoadingSkipFields={[...optionsLoadingSkipFields, 'description', 'execute_now',
+          'execute_now_options', ...migrationFields.map(f => f.name)]}
       />
     )
   }
@@ -503,6 +511,10 @@ class EditReplica extends React.Component<Props, State> {
 
     return (
       <WizardStorage
+        defaultStorage={this.getDefaultStorage()}
+        onDefaultStorageChange={defaultStorage => { this.setState({ defaultStorage }) }}
+        storageConfigDefault={endpointStore.storageConfigDefault}
+        defaultStorageLayout="modal"
         storageBackends={endpointStore.storageBackends}
         instancesDetails={this.props.instancesDetails}
         storageMap={this.getStorageMap(endpointStore.storageBackends)}

+ 0 - 9
src/components/organisms/WizardOptions/WizardOptions.jsx

@@ -196,15 +196,6 @@ class WizardOptions extends React.Component<Props> {
       fieldsSchema = [...fieldsSchema, ...migrationFields]
     }
 
-    if (this.props.hasStorageMap && this.props.useAdvancedOptions && this.props.storageBackends && this.props.storageBackends.length > 0) {
-      fieldsSchema.push({
-        name: 'default_storage',
-        type: 'string',
-        enum: this.props.storageBackends.map(s => s.name),
-        default: this.props.storageConfigDefault,
-      })
-    }
-
     return fieldsSchema
   }
 

+ 8 - 1
src/components/organisms/WizardPageContent/WizardPageContent.jsx

@@ -174,6 +174,7 @@ type Props = {
   wizardData: WizardData,
   schedules: ScheduleType[],
   storageMap: StorageMap[],
+  defaultStorage: ?string,
   hasStorageMap: boolean,
   hasSourceOptions: boolean,
   pages: WizardPage[],
@@ -192,6 +193,7 @@ type Props = {
   onSourceOptionsChange: (field: Field, value: any) => void,
   onNetworkChange: (nic: Nic, network: Network, secGroups: ?SecurityGroup[]) => void,
   onStorageChange: (sourceStorage: Disk, targetStorage: StorageBackend, type: 'backend' | 'disk') => void,
+  onDefaultStorageChange: (value: ?string) => void,
   onAddScheduleClick: (schedule: ScheduleType) => void,
   onScheduleChange: (scheduleId: string, schedule: ScheduleType) => void,
   onScheduleRemove: (scheudleId: string) => void,
@@ -431,7 +433,7 @@ class WizardPageContent extends React.Component<Props, State> {
             optionsLoading={this.props.providerStore.destinationOptionsSecondaryLoading}
             optionsLoadingSkipFields={[
               ...getOptionsLoadingSkipFields('destination'), 'description', 'execute_now',
-              'execute_now_options', 'default_storage', ...migrationFields.map(f => f.name)]}
+              'execute_now_options', ...migrationFields.map(f => f.name)]}
             selectedInstances={this.props.wizardData.selectedInstances}
             fields={this.props.providerStore.destinationSchema}
             onChange={this.props.onDestOptionsChange}
@@ -465,6 +467,10 @@ class WizardPageContent extends React.Component<Props, State> {
             instancesDetails={this.props.instanceStore.instancesDetails}
             storageMap={this.props.storageMap}
             onChange={this.props.onStorageChange}
+            storageConfigDefault={this.props.endpointStore.storageConfigDefault}
+            defaultStorage={this.props.defaultStorage}
+            onDefaultStorageChange={this.props.onDefaultStorageChange}
+            defaultStorageLayout="page"
           />
         )
         break
@@ -496,6 +502,7 @@ class WizardPageContent extends React.Component<Props, State> {
           <WizardSummary
             data={this.props.wizardData}
             schedules={this.props.schedules}
+            defaultStorage={this.props.defaultStorage}
             storageMap={this.props.storageMap}
             wizardType={this.props.type}
             instancesDetails={this.props.instanceStore.instancesDetails}

+ 34 - 1
src/components/organisms/WizardStorage/WizardStorage.jsx

@@ -20,6 +20,7 @@ import styled from 'styled-components'
 
 import AutocompleteDropdown from '../../molecules/AutocompleteDropdown'
 import Dropdown from '../../molecules/Dropdown'
+import FieldInput from '../../molecules/FieldInput'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -34,9 +35,12 @@ import arrowImage from './images/arrow.svg'
 const Wrapper = styled.div`
   width: 100%;
   display: flex;
-  justify-content: center;
+  flex-direction: column;
   overflow: auto;
 `
+const DefaultStorageWrapper = styled.div`
+  margin-bottom: 32px;
+`
 const Mapping = styled.div`
   display: flex;
   flex-direction: column;
@@ -151,6 +155,10 @@ export type Props = {
   storageBackends: StorageBackend[],
   instancesDetails: Instance[],
   storageMap: ?StorageMap[],
+  defaultStorageLayout: 'modal' | 'page',
+  defaultStorage: ?string,
+  storageConfigDefault: ?string,
+  onDefaultStorageChange: (value: ?string) => void,
   onChange: (sourceStorage: Disk, targetStorage: StorageBackend, type: 'backend' | 'disk') => void,
   style?: any,
   titleWidth?: number,
@@ -295,9 +303,34 @@ class WizardStorage extends React.Component<Props> {
     return this.renderStorageWrapper(disks, 'disk')
   }
 
+  renderDefaultStorage() {
+    let disks = getDisks(this.props.instancesDetails, 'disk', this.props.storageMap)
+
+    if (disks.length === 0 || this.props.storageBackends.length === 0) {
+      return null
+    }
+
+    return (
+      <DefaultStorageWrapper>
+        <FieldInput
+          layout={this.props.defaultStorageLayout}
+          name="default_storage"
+          type="string"
+          description="Storage type on the destination to default to"
+          enum={this.props.storageBackends.map(s => s.name)}
+          addNullValue
+          width={StyleProps.inputSizes.regular.width}
+          value={this.props.defaultStorage !== undefined ? this.props.defaultStorage : this.props.storageConfigDefault}
+          onChange={value => { this.props.onDefaultStorageChange(value) }}
+        />
+      </DefaultStorageWrapper>
+    )
+  }
+
   render() {
     return (
       <Wrapper style={this.props.style}>
+        {this.renderDefaultStorage()}
         <Mapping>
           {this.renderBackendMapping()}
           {this.renderDiskMapping()}

+ 3 - 0
src/components/organisms/WizardStorage/test.jsx

@@ -66,6 +66,9 @@ const defaultProps: Props = {
   }],
   defaultStorage: 'sback1',
   onChange: () => { },
+  defaultStorageLayout: 'page',
+  onDefaultStorageChange: () => { },
+  storageConfigDefault: null,
 }
 const wrap = (props: Props) => new TW(shallow(<Component {...props} />), TEST_ID)
 

+ 9 - 0
src/components/organisms/WizardSummary/WizardSummary.jsx

@@ -167,6 +167,7 @@ type Props = {
   data: WizardData,
   wizardType: 'replica' | 'migration',
   schedules: Schedule[],
+  defaultStorage: ?string,
   storageMap: StorageMap[],
   instancesDetails: Instance[],
   sourceSchema: Field[],
@@ -317,6 +318,13 @@ class WizardSummary extends React.Component<Props> {
       ),
     ]
 
+    let defaultStorageOption = (
+      <Option>
+        <OptionLabel>Default Storage</OptionLabel>
+        <OptionValue>{this.props.defaultStorage}</OptionValue>
+      </Option>
+    )
+
     return (
       <Section>
         <SectionTitle>{type} Target Options</SectionTitle>
@@ -324,6 +332,7 @@ class WizardSummary extends React.Component<Props> {
           {this.props.wizardType === 'replica' ? executeNowOption : null}
           {this.props.wizardType === 'migration' ? migrationOptions : null}
           {this.props.data.selectedInstances && this.props.data.selectedInstances.length > 1 ? separateVmOption : null}
+          {this.props.defaultStorage ? defaultStorageOption : null}
           {data.destOptions ? Object.keys(data.destOptions).map(optionName => {
             if (
               optionName === 'execute_now' ||

+ 9 - 0
src/components/pages/WizardPage/WizardPage.jsx

@@ -323,6 +323,11 @@ class WizardPage extends React.Component<Props, State> {
     wizardStore.updateUrlState()
   }
 
+  handleDefaultStorageChange(value: ?string) {
+    wizardStore.updateDefaultStorage(value)
+    wizardStore.updateUrlState()
+  }
+
   handleStorageChange(source: Disk, target: StorageBackend, type: 'backend' | 'disk') {
     wizardStore.updateStorage({ source, target, type })
     wizardStore.updateUrlState()
@@ -481,6 +486,7 @@ class WizardPage extends React.Component<Props, State> {
     await wizardStore.createMultiple(
       this.state.type,
       wizardStore.data,
+      wizardStore.defaultStorage,
       wizardStore.storageMap,
       wizardStore.uploadedUserScripts,
     )
@@ -500,6 +506,7 @@ class WizardPage extends React.Component<Props, State> {
       await wizardStore.create(
         this.state.type,
         wizardStore.data,
+        wizardStore.defaultStorage,
         wizardStore.storageMap,
         wizardStore.uploadedUserScripts,
       )
@@ -607,6 +614,7 @@ class WizardPage extends React.Component<Props, State> {
             wizardData={wizardStore.data}
             hasStorageMap={Boolean(this.pages.find(p => p.id === 'storage'))}
             hasSourceOptions={Boolean(this.pages.find(p => p.id === 'source-options'))}
+            defaultStorage={wizardStore.defaultStorage}
             storageMap={wizardStore.storageMap}
             schedules={wizardStore.schedules}
             nextButtonDisabled={this.isNextButtonDisabled()}
@@ -624,6 +632,7 @@ class WizardPage extends React.Component<Props, State> {
             onDestOptionsChange={(field, value) => { this.handleDestOptionsChange(field, value) }}
             onSourceOptionsChange={(field, value) => { this.handleSourceOptionsChange(field, value) }}
             onNetworkChange={(sourceNic, targetNetwork, secGroups) => { this.handleNetworkChange(sourceNic, targetNetwork, secGroups) }}
+            onDefaultStorageChange={value => { this.handleDefaultStorageChange(value) }}
             onStorageChange={(source, target, type) => { this.handleStorageChange(source, target, type) }}
             onAddScheduleClick={schedule => { this.handleAddScheduleClick(schedule) }}
             onScheduleChange={(scheduleId, data) => { this.handleScheduleChange(scheduleId, data) }}

+ 1 - 1
src/plugins/endpoint/default/OptionsSchemaPlugin.js

@@ -73,7 +73,7 @@ export const defaultFillMigrationImageMapValues = (field: Field, option: OptionV
 
 export const defaultGetDestinationEnv = (options: ?{ [string]: mixed }, oldOptions?: ?{ [string]: mixed }): any => {
   let env = {}
-  let specialOptions = ['execute_now', 'separate_vm', 'skip_os_morphing', 'default_storage', 'description']
+  let specialOptions = ['execute_now', 'separate_vm', 'skip_os_morphing', 'description']
     .concat(migrationFields.map(f => f.name))
     .concat(executionOptions.map(o => o.name))
     .concat(migrationImageOsTypes.map(o => `${o}_os_image`))

+ 1 - 1
src/sources/AssessmentSource.js

@@ -33,7 +33,7 @@ class AssessmentSourceUtils {
     if (vmSize) {
       env.vm_size = vmSize
     }
-    let skipFields = ['use_replica', 'separate_vm', 'shutdown_instances', 'skip_os_morphing', 'default_storage']
+    let skipFields = ['use_replica', 'separate_vm', 'shutdown_instances', 'skip_os_morphing']
     Object.keys(data.fieldValues).filter(f => !skipFields.find(sf => sf === f)).forEach(fieldName => {
       if (data.fieldValues[fieldName] != null) {
         env[fieldName] = data.fieldValues[fieldName]

+ 3 - 1
src/sources/MigrationSource.js

@@ -82,6 +82,8 @@ class MigrationSource {
     updatedSourceEnv?: ?{ [string]: any },
     storageMappings: ?{ [string]: any },
     updatedStorageMappings: ?StorageMap[],
+    defaultStorage: ?string,
+    updatedDefaultStorage: ?string,
     networkMappings: ?{ [string]: any },
     updatedNetworkMappings: ?NetworkMap[],
   }): Promise<MainItem> {
@@ -122,7 +124,7 @@ class MigrationSource {
       || (opts.updatedStorageMappings && opts.updatedStorageMappings.length)) {
       payload.migration.storage_mappings = {
         ...opts.storageMappings,
-        ...destParser.getStorageMap(getValue('default_storage'), opts.updatedStorageMappings),
+        ...destParser.getStorageMap(opts.updatedDefaultStorage || opts.defaultStorage, opts.updatedStorageMappings),
       }
     }
 

+ 1 - 2
src/sources/ReplicaSource.js

@@ -203,7 +203,7 @@ class ReplicaSource {
     return response.data.execution
   }
 
-  async update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, storageConfigDefault: string): Promise<Execution> {
+  async update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, defaultStorage: ?string, storageConfigDefault: string): Promise<Execution> {
     const parser = OptionsSchemaPlugin[destinationEndpoint.type] || OptionsSchemaPlugin.default
     let payload = { replica: {} }
 
@@ -219,7 +219,6 @@ class ReplicaSource {
       payload.replica.source_environment = parser.getDestinationEnv(updateData.source, replica.source_environment)
     }
 
-    let defaultStorage = updateData.destination && updateData.destination.default_storage
     if (defaultStorage || updateData.storage.length > 0) {
       payload.replica.storage_mappings = parser.getStorageMap(defaultStorage, updateData.storage, storageConfigDefault)
     }

+ 3 - 2
src/sources/WizardSource.js

@@ -28,13 +28,13 @@ class WizardSource {
   async create(
     type: string,
     data: WizardData,
+    defaultStorage: ?string,
     storageMap: StorageMap[],
     uploadedUserScripts: InstanceScript[]
   ): Promise<MainItem> {
     const sourceParser = data.source ? OptionsSchemaPlugin[data.source.type] || OptionsSchemaPlugin.default : OptionsSchemaPlugin.default
     const destParser = data.target ? OptionsSchemaPlugin[data.target.type] || OptionsSchemaPlugin.default : OptionsSchemaPlugin.default
     let payload = {}
-    let defaultStorage: ?string = data.destOptions && data.destOptions.default_storage
     payload[type] = {
       origin_endpoint_id: data.source ? data.source.id : 'null',
       destination_endpoint_id: data.target ? data.target.id : 'null',
@@ -72,6 +72,7 @@ class WizardSource {
   async createMultiple(
     type: string,
     data: WizardData,
+    defaultStorage: ?string,
     storageMap: StorageMap[],
     uploadedUserScripts: InstanceScript[]
   ): Promise<MainItem[]> {
@@ -82,7 +83,7 @@ class WizardSource {
       let newData = { ...data }
       newData.selectedInstances = [instance]
       try {
-        let mainItem: MainItem = await this.create(type, newData, storageMap, uploadedUserScripts)
+        let mainItem: MainItem = await this.create(type, newData, defaultStorage, storageMap, uploadedUserScripts)
         return mainItem
       } catch (err) {
         notificationStore.alert(`Error while creating ${type} for instance ${instance.name}`, 'error')

+ 5 - 1
src/stores/MigrationStore.js

@@ -59,7 +59,9 @@ class MigrationStore {
     migration: MainItem,
     sourceEndpoint: Endpoint,
     destEndpoint: Endpoint,
-    updateData: UpdateData
+    updateData: UpdateData,
+    defaultStorage: ?string,
+    updatedDefaultStorage: ?string
   ): Promise<MainItem> {
     let migrationResult = await MigrationSource.recreate({
       sourceEndpoint,
@@ -71,6 +73,8 @@ class MigrationStore {
       updatedDestEnv: updateData.destination,
       storageMappings: migration.storage_mappings,
       updatedStorageMappings: updateData.storage,
+      defaultStorage,
+      updatedDefaultStorage,
       networkMappings: migration.network_map,
       updatedNetworkMappings: updateData.network,
     })

+ 2 - 2
src/stores/ReplicaStore.js

@@ -185,8 +185,8 @@ class ReplicaStore {
     this.replicaDetails = null
   }
 
-  async update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, storageConfigDefault: string) {
-    await ReplicaSource.update(replica, destinationEndpoint, updateData, storageConfigDefault)
+  async update(replica: MainItem, destinationEndpoint: Endpoint, updateData: UpdateData, defaultStorage: ?string, storageConfigDefault: string) {
+    await ReplicaSource.update(replica, destinationEndpoint, updateData, defaultStorage, storageConfigDefault)
   }
 }
 

+ 18 - 3
src/stores/WizardStore.js

@@ -54,6 +54,7 @@ const updateOptions = (oldOptions: ?{ [string]: mixed }, data: { field: Field, v
 class WizardStore {
   @observable data: WizardData = {}
   @observable schedules: Schedule[] = []
+  @observable defaultStorage: ?string = null
   @observable storageMap: StorageMap[] = []
   @observable currentPage: WizardPage = wizardPages[0]
   @observable createdItem: ?MainItem = null
@@ -84,6 +85,7 @@ class WizardStore {
   @action clearData() {
     this.data = {}
     this.currentPage = wizardPages[0]
+    this.clearStorageMap()
   }
 
   @action setCurrentPage(page: WizardPage) {
@@ -109,6 +111,10 @@ class WizardStore {
     this.data.networks.push(network)
   }
 
+  @action updateDefaultStorage(value: ?string) {
+    this.defaultStorage = value
+  }
+
   @action updateStorage(storage: StorageMap) {
     let diskFieldName = storage.type === 'backend' ? 'storage_backend_identifier' : 'id'
     this.storageMap = this.storageMap
@@ -118,6 +124,7 @@ class WizardStore {
 
   @action clearStorageMap() {
     this.storageMap = []
+    this.defaultStorage = null
   }
 
   @action addSchedule(schedule: Schedule) {
@@ -151,13 +158,14 @@ class WizardStore {
   @action async create(
     type: string,
     data: WizardData,
+    defaultStorage: ?string,
     storageMap: StorageMap[],
     uploadedUserScripts: InstanceScript[]
   ): Promise<void> {
     this.creatingItem = true
 
     try {
-      let item: MainItem = await source.create(type, data, storageMap, uploadedUserScripts)
+      let item: MainItem = await source.create(type, data, defaultStorage, storageMap, uploadedUserScripts)
       runInAction(() => { this.createdItem = item })
     } catch (err) {
       throw err
@@ -169,13 +177,14 @@ class WizardStore {
   @action async createMultiple(
     type: string,
     data: WizardData,
+    defaultStorage: ?string,
     storageMap: StorageMap[],
     uploadedUserScripts: InstanceScript[]
   ): Promise<void> {
     this.creatingItems = true
 
     try {
-      let items: MainItem[] = await source.createMultiple(type, data, storageMap, uploadedUserScripts)
+      let items: MainItem[] = await source.createMultiple(type, data, defaultStorage, storageMap, uploadedUserScripts)
       runInAction(() => { this.createdItems = items })
     } finally {
       runInAction(() => { this.creatingItems = false })
@@ -183,7 +192,12 @@ class WizardStore {
   }
 
   updateUrlState() {
-    source.setUrlState({ data: this.data, schedules: this.schedules, storageMap: this.storageMap })
+    source.setUrlState({
+      data: this.data,
+      schedules: this.schedules,
+      storageMap: this.storageMap,
+      defaultStorage: this.defaultStorage,
+    })
   }
 
   @action getUrlState() {
@@ -194,6 +208,7 @@ class WizardStore {
     this.data = state.data
     this.schedules = state.schedules
     this.storageMap = state.storageMap
+    this.defaultStorage = state.defaultStorage
   }
 
   @action cancelUploadedScript(global: ?string, instanceName: ?string) {