Merge remote-tracking branch 'apache/4.19'

This commit is contained in:
Abhishek Kumar 2024-05-27 15:14:29 +05:30
commit acce88ff39
12 changed files with 100 additions and 53 deletions

View File

@ -454,6 +454,7 @@ public class ApiConstants {
public static final String TEMPLATE_IDS = "templateids"; public static final String TEMPLATE_IDS = "templateids";
public static final String TEMPLATE_NAME = "templatename"; public static final String TEMPLATE_NAME = "templatename";
public static final String TEMPLATE_TYPE = "templatetype"; public static final String TEMPLATE_TYPE = "templatetype";
public static final String TEMPLATE_FORMAT = "templateformat";
public static final String TIMEOUT = "timeout"; public static final String TIMEOUT = "timeout";
public static final String TIMEZONE = "timezone"; public static final String TIMEZONE = "timezone";
public static final String TIMEZONEOFFSET = "timezoneoffset"; public static final String TIMEZONEOFFSET = "timezoneoffset";

View File

@ -137,6 +137,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
@Param(description = "the type of the template for the virtual machine", since = "4.19.0") @Param(description = "the type of the template for the virtual machine", since = "4.19.0")
private String templateType; private String templateType;
@SerializedName(ApiConstants.TEMPLATE_FORMAT)
@Param(description = "the format of the template for the virtual machine", since = "4.19.1")
private String templateFormat;
@SerializedName("templatedisplaytext") @SerializedName("templatedisplaytext")
@Param(description = " an alternate display text of the template for the virtual machine") @Param(description = " an alternate display text of the template for the virtual machine")
private String templateDisplayText; private String templateDisplayText;
@ -1076,6 +1080,14 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
this.templateType = templateType; this.templateType = templateType;
} }
public String getTemplateFormat() {
return templateFormat;
}
public void setTemplateFormat(String templateFormat) {
this.templateFormat = templateFormat;
}
public List<VnfNicResponse> getVnfNics() { public List<VnfNicResponse> getVnfNics() {
return vnfNics; return vnfNics;
} }

View File

@ -74,6 +74,7 @@ SELECT
`vm_template`.`uuid` AS `template_uuid`, `vm_template`.`uuid` AS `template_uuid`,
`vm_template`.`name` AS `template_name`, `vm_template`.`name` AS `template_name`,
`vm_template`.`type` AS `template_type`, `vm_template`.`type` AS `template_type`,
`vm_template`.`format` AS `template_format`,
`vm_template`.`display_text` AS `template_display_text`, `vm_template`.`display_text` AS `template_display_text`,
`vm_template`.`enable_password` AS `password_enabled`, `vm_template`.`enable_password` AS `password_enabled`,
`iso`.`id` AS `iso_id`, `iso`.`id` AS `iso_id`,

View File

@ -197,6 +197,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
userVmResponse.setTemplateDisplayText(userVm.getTemplateDisplayText()); userVmResponse.setTemplateDisplayText(userVm.getTemplateDisplayText());
userVmResponse.setPasswordEnabled(userVm.isPasswordEnabled()); userVmResponse.setPasswordEnabled(userVm.isPasswordEnabled());
userVmResponse.setTemplateType(userVm.getTemplateType().toString()); userVmResponse.setTemplateType(userVm.getTemplateType().toString());
userVmResponse.setTemplateFormat(userVm.getTemplateFormat().toString());
} }
if (details.contains(VMDetails.all) || details.contains(VMDetails.iso)) { if (details.contains(VMDetails.all) || details.contains(VMDetails.iso)) {
userVmResponse.setIsoId(userVm.getIsoUuid()); userVmResponse.setIsoId(userVm.getIsoUuid());

View File

@ -35,6 +35,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Network.GuestType; import com.cloud.network.Network.GuestType;
import com.cloud.network.Networks.TrafficType; import com.cloud.network.Networks.TrafficType;
import com.cloud.resource.ResourceState; import com.cloud.resource.ResourceState;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.Storage.TemplateType;
import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Volume; import com.cloud.storage.Volume;
@ -201,6 +202,9 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
@Column(name = "template_display_text", length = 4096) @Column(name = "template_display_text", length = 4096)
private String templateDisplayText; private String templateDisplayText;
@Column(name = "template_format")
private Storage.ImageFormat templateFormat;
@Column(name = "password_enabled") @Column(name = "password_enabled")
private boolean passwordEnabled; private boolean passwordEnabled;
@ -647,6 +651,10 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
return templateDisplayText; return templateDisplayText;
} }
public Storage.ImageFormat getTemplateFormat() {
return templateFormat;
}
public boolean isPasswordEnabled() { public boolean isPasswordEnabled() {
return passwordEnabled; return passwordEnabled;
} }

View File

@ -1172,6 +1172,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
Long profileId = cmd.getProfileId(); Long profileId = cmd.getProfileId();
Long zoneId = cmd.getZoneId(); Long zoneId = cmd.getZoneId();
Boolean forDisplay = cmd.getDisplay(); Boolean forDisplay = cmd.getDisplay();
String keyword = cmd.getKeyword();
SearchWrapper<AutoScaleVmGroupVO> searchWrapper = new SearchWrapper<>(autoScaleVmGroupDao, AutoScaleVmGroupVO.class, cmd, cmd.getId()); SearchWrapper<AutoScaleVmGroupVO> searchWrapper = new SearchWrapper<>(autoScaleVmGroupDao, AutoScaleVmGroupVO.class, cmd, cmd.getId());
SearchBuilder<AutoScaleVmGroupVO> sb = searchWrapper.getSearchBuilder(); SearchBuilder<AutoScaleVmGroupVO> sb = searchWrapper.getSearchBuilder();
@ -1182,6 +1183,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
sb.and("profileId", sb.entity().getProfileId(), SearchCriteria.Op.EQ); sb.and("profileId", sb.entity().getProfileId(), SearchCriteria.Op.EQ);
sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ); sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ);
sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ); sb.and("display", sb.entity().isDisplay(), SearchCriteria.Op.EQ);
sb.and("keyword", sb.entity().getName(), SearchCriteria.Op.LIKE);
if (policyId != null) { if (policyId != null) {
SearchBuilder<AutoScaleVmGroupPolicyMapVO> asVmGroupPolicySearch = autoScaleVmGroupPolicyMapDao.createSearchBuilder(); SearchBuilder<AutoScaleVmGroupPolicyMapVO> asVmGroupPolicySearch = autoScaleVmGroupPolicyMapDao.createSearchBuilder();
@ -1211,6 +1213,9 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
if (forDisplay != null) { if (forDisplay != null) {
sc.setParameters("display", forDisplay); sc.setParameters("display", forDisplay);
} }
if (StringUtils.isNotBlank(keyword)) {
sc.setParameters("keyword", "%" + keyword + "%");
}
return searchWrapper.search(); return searchWrapper.search();
} }

View File

@ -16,20 +16,12 @@
// under the License. // under the License.
package com.cloud.api.query.dao; package com.cloud.api.query.dao;
import com.cloud.api.query.vo.UserVmJoinVO; import static org.mockito.ArgumentMatchers.nullable;
import com.cloud.storage.Storage; import static org.mockito.MockitoAnnotations.openMocks;
import com.cloud.storage.VnfTemplateDetailVO;
import com.cloud.storage.VnfTemplateNicVO; import java.util.Arrays;
import com.cloud.storage.dao.VnfTemplateDetailsDao; import java.util.EnumSet;
import com.cloud.storage.dao.VnfTemplateNicDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.UserStatisticsVO;
import com.cloud.user.dao.UserDao;
import com.cloud.user.dao.UserStatisticsDao;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.dao.UserVmDetailsDao;
import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ResponseObject; import org.apache.cloudstack.api.ResponseObject;
@ -44,11 +36,20 @@ import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays; import com.cloud.api.query.vo.UserVmJoinVO;
import java.util.EnumSet; import com.cloud.storage.Storage;
import com.cloud.storage.VnfTemplateDetailVO;
import static org.mockito.ArgumentMatchers.nullable; import com.cloud.storage.VnfTemplateNicVO;
import static org.mockito.MockitoAnnotations.openMocks; import com.cloud.storage.dao.VnfTemplateDetailsDao;
import com.cloud.storage.dao.VnfTemplateNicDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.UserStatisticsVO;
import com.cloud.user.dao.UserDao;
import com.cloud.user.dao.UserStatisticsDao;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.dao.UserVmDetailsDao;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest<UserVmJoinVO, UserVmResponse> { public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest<UserVmJoinVO, UserVmResponse> {
@ -113,6 +114,7 @@ public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseT
Mockito.when(userVmMock.getId()).thenReturn(vmId); Mockito.when(userVmMock.getId()).thenReturn(vmId);
Mockito.when(userVmMock.getTemplateId()).thenReturn(templateId); Mockito.when(userVmMock.getTemplateId()).thenReturn(templateId);
Mockito.when(userVmMock.getTemplateType()).thenReturn(Storage.TemplateType.VNF); Mockito.when(userVmMock.getTemplateType()).thenReturn(Storage.TemplateType.VNF);
Mockito.when(userVmMock.getTemplateFormat()).thenReturn(Storage.ImageFormat.OVA);
Mockito.when(caller.getId()).thenReturn(2L); Mockito.when(caller.getId()).thenReturn(2L);
Mockito.when(accountMgr.isRootAdmin(nullable(Long.class))).thenReturn(true); Mockito.when(accountMgr.isRootAdmin(nullable(Long.class))).thenReturn(true);

View File

@ -524,7 +524,7 @@
<div class="resource-detail-item__details"> <div class="resource-detail-item__details">
<resource-icon v-if="resource.icon" :image="getImage(resource.icon.base64image)" size="1x" style="margin-right: 5px"/> <resource-icon v-if="resource.icon" :image="getImage(resource.icon.base64image)" size="1x" style="margin-right: 5px"/>
<SaveOutlined v-else /> <SaveOutlined v-else />
<router-link :to="{ path: '/template/' + resource.templateid }">{{ resource.templatedisplaytext || resource.templatename || resource.templateid }} </router-link> <router-link :to="{ path: (resource.templateformat === 'ISO' ? '/iso/' : '/template/') + resource.templateid }">{{ resource.templatedisplaytext || resource.templatename || resource.templateid }} </router-link>
</div> </div>
</div> </div>
<div class="resource-detail-item" v-if="resource.isoid"> <div class="resource-detail-item" v-if="resource.isoid">

View File

@ -231,7 +231,7 @@ export default {
} }
return fields return fields
}, },
details: ['name', 'id', 'displaytext', 'checksum', 'ostypename', 'size', 'bootable', 'isready', 'passwordenabled', 'directdownload', 'isextractable', 'ispublic', 'isfeatured', 'crosszones', 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url'], details: ['name', 'id', 'displaytext', 'checksum', 'ostypename', 'size', 'bootable', 'isready', 'passwordenabled', 'directdownload', 'isextractable', 'ispublic', 'isfeatured', 'isdynamicallyscalable', 'crosszones', 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url'],
searchFilters: () => { searchFilters: () => {
var filters = ['name', 'zoneid', 'tags'] var filters = ['name', 'zoneid', 'tags']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) { if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {

View File

@ -227,35 +227,45 @@
</a-col> </a-col>
</a-row> </a-row>
<a-form-item ref="isextractable" name="isextractable"> <a-row :gutter="12">
<template #label> <a-col :md="24" :lg="12">
<tooltip-label :title="$t('label.isextractable')" :tooltip="apiParams.isextractable.description"/> <a-form-item ref="isdynamicallyscalable" name="isdynamicallyscalable">
</template> <template #label>
<a-switch v-model:checked="form.isextractable" /> <tooltip-label :title="$t('label.isdynamicallyscalable')" :tooltip="apiParams.isdynamicallyscalable.description"/>
</a-form-item> </template>
<a-switch v-model:checked="form.isdynamicallyscalable" />
<a-form-item </a-form-item>
ref="ispublic" <a-form-item
name="ispublic" ref="ispublic"
v-if="$store.getters.userInfo.roletype === 'Admin' || $store.getters.features.userpublictemplateenabled" > name="ispublic"
<template #label> v-if="$store.getters.userInfo.roletype === 'Admin' || $store.getters.features.userpublictemplateenabled" >
<tooltip-label :title="$t('label.ispublic')" :tooltip="apiParams.ispublic.description"/> <template #label>
</template> <tooltip-label :title="$t('label.ispublic')" :tooltip="apiParams.ispublic.description"/>
<a-switch v-model:checked="form.ispublic" /> </template>
</a-form-item> <a-switch v-model:checked="form.ispublic" />
</a-form-item>
<a-form-item ref="isfeatured" name="isfeatured" v-if="$store.getters.userInfo.roletype === 'Admin'"> <a-form-item ref="passwordenabled" name="passwordenabled" v-if="currentForm === 'Create'">
<template #label> <template #label>
<tooltip-label :title="$t('label.isfeatured')" :tooltip="apiParams.isfeatured.description"/> <tooltip-label :title="$t('label.passwordenabled')" :tooltip="apiParams.passwordenabled.description"/>
</template> </template>
<a-switch v-model:checked="form.isfeatured" /> <a-switch v-model:checked="form.passwordenabled" />
</a-form-item> </a-form-item>
<a-form-item ref="passwordenabled" name="passwordenabled" v-if="currentForm === 'Create'"> </a-col>
<template #label> <a-col :md="24" :lg="12">
<tooltip-label :title="$t('label.passwordenabled')" :tooltip="apiParams.passwordenabled.description"/> <a-form-item ref="isextractable" name="isextractable">
</template> <template #label>
<a-switch v-model:checked="form.passwordenabled" /> <tooltip-label :title="$t('label.isextractable')" :tooltip="apiParams.isextractable.description"/>
</a-form-item> </template>
<a-switch v-model:checked="form.isextractable" />
</a-form-item>
<a-form-item ref="isfeatured" name="isfeatured" v-if="$store.getters.userInfo.roletype === 'Admin'">
<template #label>
<tooltip-label :title="$t('label.isfeatured')" :tooltip="apiParams.isfeatured.description"/>
</template>
<a-switch v-model:checked="form.isfeatured" />
</a-form-item>
</a-col>
</a-row>
<div :span="24" class="action-button"> <div :span="24" class="action-button">
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button> <a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
@ -339,7 +349,8 @@ export default {
bootable: true, bootable: true,
isextractable: false, isextractable: false,
ispublic: false, ispublic: false,
passwordenabled: false passwordenabled: false,
isdynamicallyscalable: false
}) })
this.rules = reactive({ this.rules = reactive({
url: [{ required: true, message: this.$t('label.upload.iso.from.local') }], url: [{ required: true, message: this.$t('label.upload.iso.from.local') }],

View File

@ -67,6 +67,12 @@
</a-select-option> </a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item name="isdynamicallyscalable" ref="isdynamicallyscalable">
<template #label>
<tooltip-label :title="$t('label.isdynamicallyscalable')" :tooltip="apiParams.isdynamicallyscalable.description"/>
</template>
<a-switch v-model:checked="form.isdynamicallyscalable" />
</a-form-item>
<a-row :gutter="12"> <a-row :gutter="12">
<a-col :md="24" :lg="12"> <a-col :md="24" :lg="12">
@ -168,7 +174,7 @@ export default {
displaytext: [{ required: true, message: this.$t('message.error.required.input') }], displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
ostypeid: [{ required: true, message: this.$t('message.error.select') }] ostypeid: [{ required: true, message: this.$t('message.error.select') }]
}) })
const resourceFields = ['name', 'displaytext', 'passwordenabled', 'ostypeid', 'userdataid', 'userdatapolicy'] const resourceFields = ['name', 'displaytext', 'passwordenabled', 'isdynamicallyscalable', 'ostypeid', 'userdataid', 'userdatapolicy']
for (var field of resourceFields) { for (var field of resourceFields) {
var fieldValue = this.resource[field] var fieldValue = this.resource[field]

View File

@ -78,7 +78,7 @@
</div> </div>
<div class="rules-table__col rules-table__col--description"> <div class="rules-table__col rules-table__col--description">
<template v-if="element.description"> <template v-if="element.description">
{{ record.description }} {{ element.description }}
</template> </template>
<div v-else class="no-description"> <div v-else class="no-description">
{{ $t('message.no.description') }} {{ $t('message.no.description') }}