mirror of https://github.com/apache/cloudstack.git
Add API param and UI changes on add secondary storage page
This commit is contained in:
parent
988ca9a32a
commit
9a60a9287b
|
|
@ -29,6 +29,11 @@ import org.apache.cloudstack.api.response.ZoneResponse;
|
|||
import com.cloud.exception.DiscoveryException;
|
||||
import com.cloud.storage.ImageStore;
|
||||
import com.cloud.user.Account;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@APICommand(name = "addSecondaryStorage", description = "Adds secondary storage.", responseObject = ImageStoreResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
|
|
@ -44,6 +49,9 @@ public class AddSecondaryStorageCmd extends BaseCmd {
|
|||
@Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "The Zone ID for the secondary storage")
|
||||
protected Long zoneId;
|
||||
|
||||
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Details in key/value pairs using format details[i].keyname=keyvalue. Example: details[0].copytemplatesfromothersecondarystorages=true")
|
||||
protected Map details;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -56,6 +64,20 @@ public class AddSecondaryStorageCmd extends BaseCmd {
|
|||
return zoneId;
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
Map<String, String> detailsMap = new HashMap<>();
|
||||
if (MapUtils.isNotEmpty(details)) {
|
||||
Collection<?> props = details.values();
|
||||
for (Object prop : props) {
|
||||
HashMap<String, String> detail = (HashMap<String, String>) prop;
|
||||
for (Map.Entry<String, String> entry: detail.entrySet()) {
|
||||
detailsMap.put(entry.getKey(),entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return detailsMap;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -68,7 +90,7 @@ public class AddSecondaryStorageCmd extends BaseCmd {
|
|||
@Override
|
||||
public void execute(){
|
||||
try{
|
||||
ImageStore result = _storageService.discoverImageStore(null, getUrl(), "NFS", getZoneId(), null);
|
||||
ImageStore result = _storageService.discoverImageStore(null, getUrl(), "NFS", getZoneId(), getDetails());
|
||||
ImageStoreResponse storeResponse = null;
|
||||
if (result != null ) {
|
||||
storeResponse = _responseGenerator.createImageStoreResponse(result);
|
||||
|
|
|
|||
|
|
@ -549,7 +549,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||
}
|
||||
|
||||
if (availHypers.contains(tmplt.getHypervisorType())) {
|
||||
boolean copied = isCopyFromOtherStoragesEnabled(zoneId) && tryCopyingTemplateToImageStore(tmplt, store);
|
||||
boolean copied = imageStoreDetailsUtil.isCopyTemplatesFromOtherStoragesEnabled(storeId, zoneId) && tryCopyingTemplateToImageStore(tmplt, store);
|
||||
if (!copied) {
|
||||
tryDownloadingTemplateToImageStore(tmplt, store);
|
||||
}
|
||||
|
|
@ -763,10 +763,6 @@ public class TemplateServiceImpl implements TemplateService {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected boolean isCopyFromOtherStoragesEnabled(Long zoneId) {
|
||||
return StorageManager.COPY_TEMPLATES_FROM_OTHER_SECONDARY_STORAGES.valueIn(zoneId);
|
||||
}
|
||||
|
||||
protected void publishTemplateCreation(TemplateInfo tmplt) {
|
||||
VMTemplateVO tmpltVo = _templateDao.findById(tmplt.getId());
|
||||
|
||||
|
|
|
|||
|
|
@ -78,4 +78,16 @@ public class ImageStoreDetailsUtil {
|
|||
return getGlobalDefaultNfsVersion();
|
||||
}
|
||||
|
||||
public boolean isCopyTemplatesFromOtherStoragesEnabled(Long storeId, Long zoneId) {
|
||||
|
||||
final Map<String, String> storeDetails = imageStoreDetailsDao.getDetails(storeId);
|
||||
final String keyWithoutDots = StorageManager.COPY_TEMPLATES_FROM_OTHER_SECONDARY_STORAGES.key()
|
||||
.replace(".", "");
|
||||
|
||||
if (storeDetails != null && storeDetails.containsKey(keyWithoutDots)) {
|
||||
return Boolean.parseBoolean(storeDetails.get(keyWithoutDots));
|
||||
}
|
||||
|
||||
return StorageManager.COPY_TEMPLATES_FROM_OTHER_SECONDARY_STORAGES.valueIn(zoneId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -589,6 +589,7 @@
|
|||
"label.copy.consoleurl": "Copy console URL to clipboard",
|
||||
"label.copyid": "Copy ID",
|
||||
"label.copy.password": "Copy password",
|
||||
"label.copy.templates.from.other.secondary.storages": "Copy templates from other storages instead of fetching from URLs",
|
||||
"label.core": "Core",
|
||||
"label.core.zone.type": "Core Zone type",
|
||||
"label.counter": "Counter",
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@
|
|||
<a-form-item name="zone" ref="zone" :label="$t('label.zone')">
|
||||
<a-select
|
||||
v-model:value="form.zone"
|
||||
@change="() => {
|
||||
fetchCopyTemplatesConfig()
|
||||
checkOtherSecondaryStorages()
|
||||
}"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
|
|
@ -159,6 +163,17 @@
|
|||
<a-input v-model:value="form.secondaryStorageNFSPath"/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div v-if="form.provider === 'NFS' && showCopyTemplatesToggle">
|
||||
<a-form-item
|
||||
name="copyTemplatesFromOtherSecondaryStorages"
|
||||
ref="copyTemplatesFromOtherSecondaryStorages"
|
||||
:label="$t('label.copy.templates.from.other.secondary.storages')">
|
||||
<a-switch
|
||||
v-model:checked="form.copyTemplatesFromOtherSecondaryStorages"
|
||||
@change="onCopyTemplatesToggleChanged"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeModal">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button type="primary" ref="submit" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
|
||||
|
|
@ -191,7 +206,9 @@ export default {
|
|||
providers: ['NFS', 'SMB/CIFS', 'S3', 'Swift'],
|
||||
zones: [],
|
||||
loading: false,
|
||||
secondaryStorageNFSStaging: false
|
||||
secondaryStorageNFSStaging: false,
|
||||
showCopyTemplatesToggle: false,
|
||||
copyTemplatesTouched: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
|
@ -203,7 +220,8 @@ export default {
|
|||
this.formRef = ref()
|
||||
this.form = reactive({
|
||||
provider: 'NFS',
|
||||
secondaryStorageHttps: true
|
||||
secondaryStorageHttps: true,
|
||||
copyTemplatesFromOtherSecondaryStorages: true
|
||||
})
|
||||
this.rules = reactive({
|
||||
zone: [{ required: true, message: this.$t('label.required') }],
|
||||
|
|
@ -229,16 +247,57 @@ export default {
|
|||
closeModal () {
|
||||
this.$emit('close-action')
|
||||
},
|
||||
fetchCopyTemplatesConfig () {
|
||||
if (!this.form.zone) {
|
||||
return
|
||||
}
|
||||
|
||||
api('listConfigurations', {
|
||||
name: 'copy.templates.from.other.secondary.storages',
|
||||
zoneid: this.form.zone
|
||||
}).then(json => {
|
||||
const items =
|
||||
json?.listconfigurationsresponse?.configuration || []
|
||||
|
||||
items.forEach(item => {
|
||||
if (item.name === 'copy.templates.from.other.secondary.storages') {
|
||||
this.form.copyTemplatesFromOtherSecondaryStorages =
|
||||
item.value === 'true'
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
listZones () {
|
||||
api('listZones', { showicon: true }).then(json => {
|
||||
if (json && json.listzonesresponse && json.listzonesresponse.zone) {
|
||||
if (json?.listzonesresponse?.zone) {
|
||||
this.zones = json.listzonesresponse.zone
|
||||
|
||||
if (this.zones.length > 0) {
|
||||
this.form.zone = this.zones[0].id || ''
|
||||
this.fetchCopyTemplatesConfig()
|
||||
this.checkOtherSecondaryStorages()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
checkOtherSecondaryStorages () {
|
||||
api('listImageStores', {
|
||||
listall: true
|
||||
}).then(json => {
|
||||
const stores = json?.listimagestoresresponse?.imagestore || []
|
||||
|
||||
this.showCopyTemplatesToggle = stores.some(store => {
|
||||
if (store.providername !== 'NFS') {
|
||||
return false
|
||||
}
|
||||
|
||||
return store.zoneid !== this.form.zone || store.zoneid === this.form.zone
|
||||
})
|
||||
})
|
||||
},
|
||||
onCopyTemplatesToggleChanged (val) {
|
||||
this.copyTemplatesTouched = true
|
||||
},
|
||||
nfsURL (server, path) {
|
||||
var url
|
||||
if (path.substring(0, 1) !== '/') {
|
||||
|
|
@ -362,6 +421,23 @@ export default {
|
|||
nfsParams.url = nfsUrl
|
||||
}
|
||||
|
||||
if (
|
||||
provider === 'NFS' &&
|
||||
this.showCopyTemplatesToggle &&
|
||||
this.copyTemplatesTouched
|
||||
) {
|
||||
const copyTemplatesKey = 'copytemplatesfromothersecondarystorages'
|
||||
|
||||
const detailIdx = Object.keys(data)
|
||||
.filter(k => k.startsWith('details['))
|
||||
.map(k => parseInt(k.match(/details\[(\d+)\]/)[1]))
|
||||
.reduce((a, b) => Math.max(a, b), -1) + 1
|
||||
|
||||
data[`details[${detailIdx}].key`] = copyTemplatesKey
|
||||
data[`details[${detailIdx}].value`] =
|
||||
values.copyTemplatesFromOtherSecondaryStorages.toString()
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
|
||||
try {
|
||||
|
|
@ -402,6 +478,11 @@ export default {
|
|||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
'form.zone' () {
|
||||
this.copyTemplatesTouched = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue