mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
ui,api,server: template categorization based on os (#10773)
Adds new interface for image selection (template/iso) for an instance in UI. Old interface can still be used and it can be configured using UI configuration (config.json) OS categories/Guest OS categories have been improved with ability to create new categories, delete an existing category, and marking a category as featured to allow it to show up in the UI in the image selection interface. New APIs added: - addOsCategory - deleteOsCategory - updateOsCategory APIs updated: - updateOsType - listTemplates - listOsCategories Several improvements in UI especially related to forms - DeloyVM, ReinstallVM, CreateVnfAppliance, AddAutoscaleGroup. DeployVM form can now be opened from template/ISO details view with query params. Reorganized (removed and added some) OS categories to the following (in the same order): ``` 1. Ubuntu 2. Debian 3. Fedora 4. CentOS 5. Rocky Linux 6. Alma Linux 7. Oracle 8. RedHat 9. SUSE 10. Windows 11. Other ``` Documentation PR: https://github.com/apache/cloudstack-documentation/pull/500 Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
41b4f0afd5
commit
bce17b627d
@ -688,6 +688,9 @@ public class EventTypes {
|
|||||||
public static final String EVENT_EXTERNAL_OPENDAYLIGHT_CONFIGURE_CONTROLLER = "PHYSICAL.ODLCONTROLLER.CONFIGURE";
|
public static final String EVENT_EXTERNAL_OPENDAYLIGHT_CONFIGURE_CONTROLLER = "PHYSICAL.ODLCONTROLLER.CONFIGURE";
|
||||||
|
|
||||||
//Guest OS related events
|
//Guest OS related events
|
||||||
|
public static final String EVENT_GUEST_OS_CATEGORY_ADD = "GUEST.OS.CATEGORY.ADD";
|
||||||
|
public static final String EVENT_GUEST_OS_CATEGORY_DELETE = "GUEST.OS.CATEGORY.DELETE";
|
||||||
|
public static final String EVENT_GUEST_OS_CATEGORY_UPDATE = "GUEST.OS.CATEGORY.UPDATE";
|
||||||
public static final String EVENT_GUEST_OS_ADD = "GUEST.OS.ADD";
|
public static final String EVENT_GUEST_OS_ADD = "GUEST.OS.ADD";
|
||||||
public static final String EVENT_GUEST_OS_REMOVE = "GUEST.OS.REMOVE";
|
public static final String EVENT_GUEST_OS_REMOVE = "GUEST.OS.REMOVE";
|
||||||
public static final String EVENT_GUEST_OS_UPDATE = "GUEST.OS.UPDATE";
|
public static final String EVENT_GUEST_OS_UPDATE = "GUEST.OS.UPDATE";
|
||||||
|
|||||||
@ -25,12 +25,15 @@ import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
|
|||||||
import org.apache.cloudstack.api.command.admin.config.ListCfgGroupsByCmd;
|
import org.apache.cloudstack.api.command.admin.config.ListCfgGroupsByCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd;
|
import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCategoryCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCmd;
|
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsMappingCmd;
|
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsMappingCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.DeleteGuestOsCategoryCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.GetHypervisorGuestOsNamesCmd;
|
import org.apache.cloudstack.api.command.admin.guest.GetHypervisorGuestOsNamesCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.ListGuestOsMappingCmd;
|
import org.apache.cloudstack.api.command.admin.guest.ListGuestOsMappingCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsCmd;
|
import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsMappingCmd;
|
import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsMappingCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsCategoryCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsCmd;
|
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsMappingCmd;
|
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsMappingCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
|
import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
|
||||||
@ -168,6 +171,12 @@ public interface ManagementService {
|
|||||||
*/
|
*/
|
||||||
Pair<List<? extends GuestOsCategory>, Integer> listGuestOSCategoriesByCriteria(ListGuestOsCategoriesCmd cmd);
|
Pair<List<? extends GuestOsCategory>, Integer> listGuestOSCategoriesByCriteria(ListGuestOsCategoriesCmd cmd);
|
||||||
|
|
||||||
|
GuestOsCategory addGuestOsCategory(AddGuestOsCategoryCmd cmd);
|
||||||
|
|
||||||
|
GuestOsCategory updateGuestOsCategory(UpdateGuestOsCategoryCmd cmd);
|
||||||
|
|
||||||
|
boolean deleteGuestOsCategory(DeleteGuestOsCategoryCmd cmd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a list of all guest OS mappings
|
* Obtains a list of all guest OS mappings
|
||||||
*
|
*
|
||||||
|
|||||||
@ -16,7 +16,9 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.server;
|
package com.cloud.server;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface ResourceIconManager {
|
public interface ResourceIconManager {
|
||||||
|
|
||||||
@ -25,4 +27,8 @@ public interface ResourceIconManager {
|
|||||||
boolean deleteResourceIcon(List<String> resourceIds, ResourceTag.ResourceObjectType resourceType);
|
boolean deleteResourceIcon(List<String> resourceIds, ResourceTag.ResourceObjectType resourceType);
|
||||||
|
|
||||||
ResourceIcon getByResourceTypeAndUuid(ResourceTag.ResourceObjectType type, String resourceId);
|
ResourceIcon getByResourceTypeAndUuid(ResourceTag.ResourceObjectType type, String resourceId);
|
||||||
|
|
||||||
|
Map<Long, ResourceIcon> getByResourceTypeAndIds(ResourceTag.ResourceObjectType type, Collection<Long> resourceIds);
|
||||||
|
|
||||||
|
Map<String, ResourceIcon> getByResourceTypeAndUuids(ResourceTag.ResourceObjectType type, Collection<String> resourceUuids);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,6 +66,7 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
|
|||||||
LBStickinessPolicy(false, true),
|
LBStickinessPolicy(false, true),
|
||||||
LBHealthCheckPolicy(false, true),
|
LBHealthCheckPolicy(false, true),
|
||||||
SnapshotPolicy(true, true),
|
SnapshotPolicy(true, true),
|
||||||
|
GuestOsCategory(false, false, true),
|
||||||
GuestOs(false, true),
|
GuestOs(false, true),
|
||||||
NetworkOffering(false, true),
|
NetworkOffering(false, true),
|
||||||
VpcOffering(true, false),
|
VpcOffering(true, false),
|
||||||
|
|||||||
@ -16,6 +16,8 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.storage;
|
package com.cloud.storage;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.Identity;
|
import org.apache.cloudstack.api.Identity;
|
||||||
import org.apache.cloudstack.api.InternalIdentity;
|
import org.apache.cloudstack.api.InternalIdentity;
|
||||||
|
|
||||||
@ -27,4 +29,7 @@ public interface GuestOsCategory extends Identity, InternalIdentity {
|
|||||||
|
|
||||||
void setName(String name);
|
void setName(String name);
|
||||||
|
|
||||||
|
boolean isFeatured();
|
||||||
|
|
||||||
|
Date getCreated();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,7 @@ public enum ApiCommandResourceType {
|
|||||||
AffinityGroup(org.apache.cloudstack.affinity.AffinityGroup.class),
|
AffinityGroup(org.apache.cloudstack.affinity.AffinityGroup.class),
|
||||||
InternalLbVm(com.cloud.network.router.VirtualRouter.class),
|
InternalLbVm(com.cloud.network.router.VirtualRouter.class),
|
||||||
DedicatedGuestVlanRange(com.cloud.network.GuestVlan.class),
|
DedicatedGuestVlanRange(com.cloud.network.GuestVlan.class),
|
||||||
|
GuestOsCategory(com.cloud.storage.GuestOsCategory.class),
|
||||||
GuestOs(com.cloud.storage.GuestOS.class),
|
GuestOs(com.cloud.storage.GuestOS.class),
|
||||||
GuestOsMapping(com.cloud.storage.GuestOSHypervisor.class),
|
GuestOsMapping(com.cloud.storage.GuestOSHypervisor.class),
|
||||||
Network(com.cloud.network.Network.class),
|
Network(com.cloud.network.Network.class),
|
||||||
|
|||||||
@ -299,6 +299,7 @@ public class ApiConstants {
|
|||||||
public static final String IS_EXTRACTABLE = "isextractable";
|
public static final String IS_EXTRACTABLE = "isextractable";
|
||||||
public static final String IS_FEATURED = "isfeatured";
|
public static final String IS_FEATURED = "isfeatured";
|
||||||
public static final String IS_IMPLICIT = "isimplicit";
|
public static final String IS_IMPLICIT = "isimplicit";
|
||||||
|
public static final String IS_ISO = "isiso";
|
||||||
public static final String IS_PORTABLE = "isportable";
|
public static final String IS_PORTABLE = "isportable";
|
||||||
public static final String IS_PUBLIC = "ispublic";
|
public static final String IS_PUBLIC = "ispublic";
|
||||||
public static final String IS_PERSISTENT = "ispersistent";
|
public static final String IS_PERSISTENT = "ispersistent";
|
||||||
|
|||||||
@ -22,20 +22,16 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.cloud.bgp.ASNumber;
|
|
||||||
import com.cloud.bgp.ASNumberRange;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.storage.object.Bucket;
|
|
||||||
import org.apache.cloudstack.affinity.AffinityGroup;
|
import org.apache.cloudstack.affinity.AffinityGroup;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
||||||
import org.apache.cloudstack.api.ApiConstants.HostDetails;
|
import org.apache.cloudstack.api.ApiConstants.HostDetails;
|
||||||
import org.apache.cloudstack.api.ApiConstants.VMDetails;
|
import org.apache.cloudstack.api.ApiConstants.VMDetails;
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
|
import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
|
||||||
import org.apache.cloudstack.api.response.AccountResponse;
|
|
||||||
import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse;
|
|
||||||
import org.apache.cloudstack.api.response.ASNRangeResponse;
|
import org.apache.cloudstack.api.response.ASNRangeResponse;
|
||||||
import org.apache.cloudstack.api.response.ASNumberResponse;
|
import org.apache.cloudstack.api.response.ASNumberResponse;
|
||||||
|
import org.apache.cloudstack.api.response.AccountResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse;
|
||||||
import org.apache.cloudstack.api.response.AsyncJobResponse;
|
import org.apache.cloudstack.api.response.AsyncJobResponse;
|
||||||
import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
|
import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
|
||||||
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
||||||
@ -60,10 +56,10 @@ import org.apache.cloudstack.api.response.DomainResponse;
|
|||||||
import org.apache.cloudstack.api.response.DomainRouterResponse;
|
import org.apache.cloudstack.api.response.DomainRouterResponse;
|
||||||
import org.apache.cloudstack.api.response.EventResponse;
|
import org.apache.cloudstack.api.response.EventResponse;
|
||||||
import org.apache.cloudstack.api.response.ExtractResponse;
|
import org.apache.cloudstack.api.response.ExtractResponse;
|
||||||
import org.apache.cloudstack.api.response.SharedFSResponse;
|
|
||||||
import org.apache.cloudstack.api.response.FirewallResponse;
|
import org.apache.cloudstack.api.response.FirewallResponse;
|
||||||
import org.apache.cloudstack.api.response.FirewallRuleResponse;
|
import org.apache.cloudstack.api.response.FirewallRuleResponse;
|
||||||
import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse;
|
import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
import org.apache.cloudstack.api.response.GuestOSResponse;
|
import org.apache.cloudstack.api.response.GuestOSResponse;
|
||||||
import org.apache.cloudstack.api.response.GuestOsMappingResponse;
|
import org.apache.cloudstack.api.response.GuestOsMappingResponse;
|
||||||
import org.apache.cloudstack.api.response.GuestVlanRangeResponse;
|
import org.apache.cloudstack.api.response.GuestVlanRangeResponse;
|
||||||
@ -73,11 +69,11 @@ import org.apache.cloudstack.api.response.HostResponse;
|
|||||||
import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
|
import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
|
||||||
import org.apache.cloudstack.api.response.HypervisorGuestOsNamesResponse;
|
import org.apache.cloudstack.api.response.HypervisorGuestOsNamesResponse;
|
||||||
import org.apache.cloudstack.api.response.IPAddressResponse;
|
import org.apache.cloudstack.api.response.IPAddressResponse;
|
||||||
import org.apache.cloudstack.api.response.IpQuarantineResponse;
|
|
||||||
import org.apache.cloudstack.api.response.ImageStoreResponse;
|
import org.apache.cloudstack.api.response.ImageStoreResponse;
|
||||||
import org.apache.cloudstack.api.response.InstanceGroupResponse;
|
import org.apache.cloudstack.api.response.InstanceGroupResponse;
|
||||||
import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse;
|
import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse;
|
||||||
import org.apache.cloudstack.api.response.IpForwardingRuleResponse;
|
import org.apache.cloudstack.api.response.IpForwardingRuleResponse;
|
||||||
|
import org.apache.cloudstack.api.response.IpQuarantineResponse;
|
||||||
import org.apache.cloudstack.api.response.IsolationMethodResponse;
|
import org.apache.cloudstack.api.response.IsolationMethodResponse;
|
||||||
import org.apache.cloudstack.api.response.LBHealthCheckResponse;
|
import org.apache.cloudstack.api.response.LBHealthCheckResponse;
|
||||||
import org.apache.cloudstack.api.response.LBStickinessResponse;
|
import org.apache.cloudstack.api.response.LBStickinessResponse;
|
||||||
@ -115,6 +111,7 @@ import org.apache.cloudstack.api.response.SecondaryStorageHeuristicsResponse;
|
|||||||
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
||||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.ServiceResponse;
|
import org.apache.cloudstack.api.response.ServiceResponse;
|
||||||
|
import org.apache.cloudstack.api.response.SharedFSResponse;
|
||||||
import org.apache.cloudstack.api.response.Site2SiteCustomerGatewayResponse;
|
import org.apache.cloudstack.api.response.Site2SiteCustomerGatewayResponse;
|
||||||
import org.apache.cloudstack.api.response.Site2SiteVpnConnectionResponse;
|
import org.apache.cloudstack.api.response.Site2SiteVpnConnectionResponse;
|
||||||
import org.apache.cloudstack.api.response.Site2SiteVpnGatewayResponse;
|
import org.apache.cloudstack.api.response.Site2SiteVpnGatewayResponse;
|
||||||
@ -159,10 +156,14 @@ import org.apache.cloudstack.region.PortableIp;
|
|||||||
import org.apache.cloudstack.region.PortableIpRange;
|
import org.apache.cloudstack.region.PortableIpRange;
|
||||||
import org.apache.cloudstack.region.Region;
|
import org.apache.cloudstack.region.Region;
|
||||||
import org.apache.cloudstack.secstorage.heuristics.Heuristic;
|
import org.apache.cloudstack.secstorage.heuristics.Heuristic;
|
||||||
import org.apache.cloudstack.storage.sharedfs.SharedFS;
|
import org.apache.cloudstack.storage.object.Bucket;
|
||||||
import org.apache.cloudstack.storage.object.ObjectStore;
|
import org.apache.cloudstack.storage.object.ObjectStore;
|
||||||
|
import org.apache.cloudstack.storage.sharedfs.SharedFS;
|
||||||
import org.apache.cloudstack.usage.Usage;
|
import org.apache.cloudstack.usage.Usage;
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
||||||
|
|
||||||
|
import com.cloud.bgp.ASNumber;
|
||||||
|
import com.cloud.bgp.ASNumberRange;
|
||||||
import com.cloud.capacity.Capacity;
|
import com.cloud.capacity.Capacity;
|
||||||
import com.cloud.configuration.ResourceCount;
|
import com.cloud.configuration.ResourceCount;
|
||||||
import com.cloud.configuration.ResourceLimit;
|
import com.cloud.configuration.ResourceLimit;
|
||||||
@ -223,10 +224,11 @@ import com.cloud.projects.ProjectAccount;
|
|||||||
import com.cloud.projects.ProjectInvitation;
|
import com.cloud.projects.ProjectInvitation;
|
||||||
import com.cloud.region.ha.GlobalLoadBalancerRule;
|
import com.cloud.region.ha.GlobalLoadBalancerRule;
|
||||||
import com.cloud.resource.RollingMaintenanceManager;
|
import com.cloud.resource.RollingMaintenanceManager;
|
||||||
import com.cloud.server.ResourceTag;
|
|
||||||
import com.cloud.server.ResourceIcon;
|
import com.cloud.server.ResourceIcon;
|
||||||
|
import com.cloud.server.ResourceTag;
|
||||||
import com.cloud.storage.GuestOS;
|
import com.cloud.storage.GuestOS;
|
||||||
import com.cloud.storage.GuestOSHypervisor;
|
import com.cloud.storage.GuestOSHypervisor;
|
||||||
|
import com.cloud.storage.GuestOsCategory;
|
||||||
import com.cloud.storage.ImageStore;
|
import com.cloud.storage.ImageStore;
|
||||||
import com.cloud.storage.Snapshot;
|
import com.cloud.storage.Snapshot;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
@ -240,14 +242,13 @@ import com.cloud.user.User;
|
|||||||
import com.cloud.user.UserAccount;
|
import com.cloud.user.UserAccount;
|
||||||
import com.cloud.user.UserData;
|
import com.cloud.user.UserData;
|
||||||
import com.cloud.uservm.UserVm;
|
import com.cloud.uservm.UserVm;
|
||||||
import com.cloud.utils.net.Ip;
|
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.net.Ip;
|
||||||
import com.cloud.vm.InstanceGroup;
|
import com.cloud.vm.InstanceGroup;
|
||||||
import com.cloud.vm.Nic;
|
import com.cloud.vm.Nic;
|
||||||
import com.cloud.vm.NicSecondaryIp;
|
import com.cloud.vm.NicSecondaryIp;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.snapshot.VMSnapshot;
|
import com.cloud.vm.snapshot.VMSnapshot;
|
||||||
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
|
||||||
|
|
||||||
public interface ResponseGenerator {
|
public interface ResponseGenerator {
|
||||||
UserResponse createUserResponse(UserAccount user);
|
UserResponse createUserResponse(UserAccount user);
|
||||||
@ -485,6 +486,10 @@ public interface ResponseGenerator {
|
|||||||
|
|
||||||
AutoScaleVmGroupResponse createAutoScaleVmGroupResponse(AutoScaleVmGroup vmGroup);
|
AutoScaleVmGroupResponse createAutoScaleVmGroupResponse(AutoScaleVmGroup vmGroup);
|
||||||
|
|
||||||
|
GuestOSCategoryResponse createGuestOSCategoryResponse(GuestOsCategory guestOsCategory);
|
||||||
|
|
||||||
|
GuestOSCategoryResponse createGuestOSCategoryResponse(GuestOsCategory guestOsCategory, boolean showIcon);
|
||||||
|
|
||||||
GuestOSResponse createGuestOSResponse(GuestOS os);
|
GuestOSResponse createGuestOSResponse(GuestOS os);
|
||||||
|
|
||||||
GuestOsMappingResponse createGuestOSMappingResponse(GuestOSHypervisor osHypervisor);
|
GuestOsMappingResponse createGuestOSMappingResponse(GuestOSHypervisor osHypervisor);
|
||||||
@ -572,4 +577,6 @@ public interface ResponseGenerator {
|
|||||||
BackupRepositoryResponse createBackupRepositoryResponse(BackupRepository repository);
|
BackupRepositoryResponse createBackupRepositoryResponse(BackupRepository repository);
|
||||||
|
|
||||||
SharedFSResponse createSharedFSResponse(ResponseView view, SharedFS sharedFS);
|
SharedFSResponse createSharedFSResponse(ResponseView view, SharedFS sharedFS);
|
||||||
|
|
||||||
|
void updateTemplateIsoResponsesForIcons(List<TemplateResponse> responses, ResourceTag.ResourceObjectType type);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,93 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package org.apache.cloudstack.api.command.admin.guest;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
|
|
||||||
|
import com.cloud.storage.GuestOsCategory;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
|
||||||
|
@APICommand(name = "addOsCategory",
|
||||||
|
description = "Adds a new OS category",
|
||||||
|
responseObject = GuestOSCategoryResponse.class,
|
||||||
|
requestHasSensitiveInfo = false,
|
||||||
|
responseHasSensitiveInfo = false,
|
||||||
|
since = "4.21.0",
|
||||||
|
authorized = {RoleType.Admin})
|
||||||
|
public class AddGuestOsCategoryCmd extends BaseCmd {
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "Name of the OS category",
|
||||||
|
required = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_FEATURED, type = CommandType.BOOLEAN,
|
||||||
|
description = "Whether the category is featured or not")
|
||||||
|
private Boolean featured;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFeatured() {
|
||||||
|
return Boolean.TRUE.equals(featured);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////// API Implementation///////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
GuestOsCategory guestOs = _mgr.addGuestOsCategory(this);
|
||||||
|
if (guestOs != null) {
|
||||||
|
GuestOSCategoryResponse response = _responseGenerator.createGuestOSCategoryResponse(guestOs);
|
||||||
|
response.setResponseName(getCommandName());
|
||||||
|
setResponseObject(response);
|
||||||
|
} else {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add new OS category");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
return Account.ACCOUNT_ID_SYSTEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiCommandResourceType getApiResourceType() {
|
||||||
|
return ApiCommandResourceType.GuestOsCategory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package org.apache.cloudstack.api.command.admin.guest;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
|
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||||
|
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
|
||||||
|
|
||||||
|
@APICommand(name = "deleteOsCategory",
|
||||||
|
description = "Deletes an OS category",
|
||||||
|
responseObject = SuccessResponse.class,
|
||||||
|
requestHasSensitiveInfo = false,
|
||||||
|
responseHasSensitiveInfo = false,
|
||||||
|
since = "4.21.0",
|
||||||
|
authorized = {RoleType.Admin})
|
||||||
|
public class DeleteGuestOsCategoryCmd extends BaseCmd {
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuestOSCategoryResponse.class,
|
||||||
|
required = true, description = "ID of the OS category")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////// API Implementation///////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
boolean result = _mgr.deleteGuestOsCategory(this);
|
||||||
|
if (result) {
|
||||||
|
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||||
|
setResponseObject(response);
|
||||||
|
} else {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove OS category");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
return Account.ACCOUNT_ID_SYSTEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiCommandResourceType getApiResourceType() {
|
||||||
|
return ApiCommandResourceType.GuestOsCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getApiResourceId() {
|
||||||
|
return getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package org.apache.cloudstack.api.command.admin.guest;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
|
|
||||||
|
import com.cloud.storage.GuestOsCategory;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
|
||||||
|
@APICommand(name = "updateOsCategory",
|
||||||
|
description = "Updates an OS category",
|
||||||
|
responseObject = GuestOSCategoryResponse.class,
|
||||||
|
requestHasSensitiveInfo = false,
|
||||||
|
responseHasSensitiveInfo = false,
|
||||||
|
since = "4.21.0",
|
||||||
|
authorized = {RoleType.Admin})
|
||||||
|
public class UpdateGuestOsCategoryCmd extends BaseCmd {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuestOSCategoryResponse.class,
|
||||||
|
required = true, description = "ID of the OS category")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "Name for the OS category")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_FEATURED, type = CommandType.BOOLEAN,
|
||||||
|
description = "Whether the category is featured or not")
|
||||||
|
private Boolean featured;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.SORT_KEY, type = CommandType.INTEGER,
|
||||||
|
description = "sort key of the OS category for listing")
|
||||||
|
private Integer sortKey;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isFeatured() {
|
||||||
|
return featured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortKey() {
|
||||||
|
return sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////// API Implementation///////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
return Account.ACCOUNT_ID_SYSTEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
GuestOsCategory guestOs = _mgr.updateGuestOsCategory(this);
|
||||||
|
if (guestOs != null) {
|
||||||
|
GuestOSCategoryResponse response = _responseGenerator.createGuestOSCategoryResponse(guestOs);
|
||||||
|
response.setResponseName(getCommandName());
|
||||||
|
setResponseObject(response);
|
||||||
|
} else {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update OS category");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiCommandResourceType getApiResourceType() {
|
||||||
|
return ApiCommandResourceType.GuestOsCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getApiResourceId() {
|
||||||
|
return getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,8 +16,12 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.command.admin.guest;
|
package org.apache.cloudstack.api.command.admin.guest;
|
||||||
|
|
||||||
import org.apache.commons.collections.MapUtils;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
@ -25,18 +29,14 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
|||||||
import org.apache.cloudstack.api.BaseAsyncCmd;
|
import org.apache.cloudstack.api.BaseAsyncCmd;
|
||||||
import org.apache.cloudstack.api.Parameter;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
import org.apache.cloudstack.api.response.GuestOSResponse;
|
import org.apache.cloudstack.api.response.GuestOSResponse;
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
|
||||||
import com.cloud.event.EventTypes;
|
import com.cloud.event.EventTypes;
|
||||||
import com.cloud.storage.GuestOS;
|
import com.cloud.storage.GuestOS;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@APICommand(name = "updateGuestOs", description = "Updates the information about Guest OS", responseObject = GuestOSResponse.class,
|
@APICommand(name = "updateGuestOs", description = "Updates the information about Guest OS", responseObject = GuestOSResponse.class,
|
||||||
since = "4.4.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
since = "4.4.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||||
public class UpdateGuestOsCmd extends BaseAsyncCmd {
|
public class UpdateGuestOsCmd extends BaseAsyncCmd {
|
||||||
@ -50,7 +50,7 @@ public class UpdateGuestOsCmd extends BaseAsyncCmd {
|
|||||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuestOSResponse.class, required = true, description = "UUID of the Guest OS")
|
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuestOSResponse.class, required = true, description = "UUID of the Guest OS")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.OS_DISPLAY_NAME, type = CommandType.STRING, required = true, description = "Unique display name for Guest OS")
|
@Parameter(name = ApiConstants.OS_DISPLAY_NAME, type = CommandType.STRING, description = "Unique display name for Guest OS")
|
||||||
private String osDisplayName;
|
private String osDisplayName;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = false, description = "Map of (key/value pairs)")
|
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = false, description = "Map of (key/value pairs)")
|
||||||
@ -59,6 +59,12 @@ public class UpdateGuestOsCmd extends BaseAsyncCmd {
|
|||||||
@Parameter(name="forDisplay", type=CommandType.BOOLEAN, description="whether this guest OS is available for end users", authorized = {RoleType.Admin})
|
@Parameter(name="forDisplay", type=CommandType.BOOLEAN, description="whether this guest OS is available for end users", authorized = {RoleType.Admin})
|
||||||
private Boolean display;
|
private Boolean display;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.OS_CATEGORY_ID, type = CommandType.UUID, entityType = GuestOSCategoryResponse.class,
|
||||||
|
description = "the ID of the OS category", since = "4.21.0")
|
||||||
|
private Long osCategoryId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -71,9 +77,9 @@ public class UpdateGuestOsCmd extends BaseAsyncCmd {
|
|||||||
return osDisplayName;
|
return osDisplayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map getDetails() {
|
public Map<String, String> getDetails() {
|
||||||
Map<String, String> detailsMap = new HashMap<>();;
|
Map<String, String> detailsMap = new HashMap<>();
|
||||||
if (MapUtils.isNotEmpty(detailsMap)) {
|
if (MapUtils.isNotEmpty(details)) {
|
||||||
Collection<?> servicesCollection = details.values();
|
Collection<?> servicesCollection = details.values();
|
||||||
Iterator<?> iter = servicesCollection.iterator();
|
Iterator<?> iter = servicesCollection.iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
@ -90,6 +96,10 @@ public class UpdateGuestOsCmd extends BaseAsyncCmd {
|
|||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getOsCategoryId() {
|
||||||
|
return osCategoryId;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -26,7 +26,9 @@ import org.apache.cloudstack.api.BaseListCmd;
|
|||||||
import org.apache.cloudstack.api.Parameter;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
|
|
||||||
|
import com.cloud.cpu.CPU;
|
||||||
import com.cloud.storage.GuestOsCategory;
|
import com.cloud.storage.GuestOsCategory;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
|
|
||||||
@ -39,12 +41,48 @@ public class ListGuestOsCategoriesCmd extends BaseListCmd {
|
|||||||
//////////////// API parameters /////////////////////
|
//////////////// API parameters /////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuestOSCategoryResponse.class, description = "list Os category by id")
|
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuestOSCategoryResponse.class, description = "List OS category by id")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "list os category by name", since = "3.0.1")
|
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "List OS category by name", since = "3.0.1")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_FEATURED,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
description = "List available OS categories by featured or not",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Boolean featured;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_ISO,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
description = "List OS categories for which an ISO is available",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Boolean iso;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_VNF, type = CommandType.BOOLEAN,
|
||||||
|
description = "List OS categories for which a VNF template is available",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Boolean vnf;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ZONE_ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = ZoneResponse.class,
|
||||||
|
description = "List available OS categories types for the zone",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Long zoneId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ARCH,
|
||||||
|
type = CommandType.STRING,
|
||||||
|
description = "List OS categories types available for given CPU architecture",
|
||||||
|
since = "4.21.0")
|
||||||
|
private String arch;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.SHOW_RESOURCE_ICON,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
description = "flag to display the resource image for the OS category",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Boolean showIcon;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -57,6 +95,30 @@ public class ListGuestOsCategoriesCmd extends BaseListCmd {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isFeatured() {
|
||||||
|
return featured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isIso() {
|
||||||
|
return iso;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isVnf() {
|
||||||
|
return vnf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPU.CPUArch getArch() {
|
||||||
|
return arch == null ? null : CPU.CPUArch.fromType(arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShowIcon() {
|
||||||
|
return Boolean.TRUE.equals(showIcon);
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -64,14 +126,11 @@ public class ListGuestOsCategoriesCmd extends BaseListCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
Pair<List<? extends GuestOsCategory>, Integer> result = _mgr.listGuestOSCategoriesByCriteria(this);
|
Pair<List<? extends GuestOsCategory>, Integer> result = _mgr.listGuestOSCategoriesByCriteria(this);
|
||||||
ListResponse<GuestOSCategoryResponse> response = new ListResponse<GuestOSCategoryResponse>();
|
ListResponse<GuestOSCategoryResponse> response = new ListResponse<>();
|
||||||
List<GuestOSCategoryResponse> osCatResponses = new ArrayList<GuestOSCategoryResponse>();
|
List<GuestOSCategoryResponse> osCatResponses = new ArrayList<>();
|
||||||
for (GuestOsCategory osCategory : result.first()) {
|
for (GuestOsCategory osCategory : result.first()) {
|
||||||
GuestOSCategoryResponse categoryResponse = new GuestOSCategoryResponse();
|
GuestOSCategoryResponse categoryResponse = _responseGenerator.createGuestOSCategoryResponse(osCategory,
|
||||||
categoryResponse.setId(osCategory.getUuid());
|
isShowIcon());
|
||||||
categoryResponse.setName(osCategory.getName());
|
|
||||||
|
|
||||||
categoryResponse.setObjectName("oscategory");
|
|
||||||
osCatResponses.add(categoryResponse);
|
osCatResponses.add(categoryResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,11 +16,6 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.command.user.iso;
|
package org.apache.cloudstack.api.command.user.iso;
|
||||||
|
|
||||||
import com.cloud.cpu.CPU;
|
|
||||||
import com.cloud.server.ResourceIcon;
|
|
||||||
import com.cloud.server.ResourceTag;
|
|
||||||
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
@ -28,16 +23,17 @@ import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
|
|||||||
import org.apache.cloudstack.api.Parameter;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
import org.apache.cloudstack.api.command.user.UserCmd;
|
import org.apache.cloudstack.api.command.user.UserCmd;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
|
||||||
import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
|
|
||||||
import com.cloud.user.Account;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import com.cloud.cpu.CPU;
|
||||||
|
import com.cloud.server.ResourceTag;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
|
||||||
@APICommand(name = "listIsos", description = "Lists all available ISO files.", responseObject = TemplateResponse.class, responseView = ResponseView.Restricted,
|
@APICommand(name = "listIsos", description = "Lists all available ISO files.", responseObject = TemplateResponse.class, responseView = ResponseView.Restricted,
|
||||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||||
@ -95,6 +91,11 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd implements UserCmd {
|
|||||||
since = "4.20")
|
since = "4.20")
|
||||||
private String arch;
|
private String arch;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.OS_CATEGORY_ID, type = CommandType.UUID, entityType= GuestOSCategoryResponse.class,
|
||||||
|
description = "the ID of the OS category for the ISO",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Long osCategoryId;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -173,6 +174,10 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd implements UserCmd {
|
|||||||
return CPU.CPUArch.fromType(arch);
|
return CPU.CPUArch.fromType(arch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getOsCategoryId() {
|
||||||
|
return osCategoryId;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -190,24 +195,14 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd implements UserCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
ListResponse<TemplateResponse> response = _queryService.listIsos(this);
|
ListResponse<TemplateResponse> response = _queryService.listIsos(this);
|
||||||
if (response != null && response.getCount() > 0 && getShowIcon()) {
|
if (response != null && getShowIcon()) {
|
||||||
updateIsoResponse(response.getResponses());
|
_responseGenerator.updateTemplateIsoResponsesForIcons(response.getResponses(),
|
||||||
|
ResourceTag.ResourceObjectType.ISO);
|
||||||
}
|
}
|
||||||
response.setResponseName(getCommandName());
|
response.setResponseName(getCommandName());
|
||||||
setResponseObject(response);
|
setResponseObject(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateIsoResponse(List<TemplateResponse> response) {
|
|
||||||
for (TemplateResponse templateResponse : response) {
|
|
||||||
ResourceIcon resourceIcon = resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.ISO, templateResponse.getId());
|
|
||||||
if (resourceIcon == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ResourceIconResponse iconResponse = _responseGenerator.createResourceIconResponse(resourceIcon);
|
|
||||||
templateResponse.setResourceIconResponse(iconResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getStoragePoolId() {
|
public Long getStoragePoolId() {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,17 +16,11 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.command.user.template;
|
package org.apache.cloudstack.api.command.user.template;
|
||||||
|
|
||||||
import com.cloud.cpu.CPU;
|
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
|
||||||
import com.cloud.server.ResourceIcon;
|
|
||||||
import com.cloud.server.ResourceTag;
|
|
||||||
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
@ -34,15 +28,20 @@ import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
|
|||||||
import org.apache.cloudstack.api.Parameter;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
import org.apache.cloudstack.api.command.user.UserCmd;
|
import org.apache.cloudstack.api.command.user.UserCmd;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.cloud.cpu.CPU;
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import com.cloud.server.ResourceTag;
|
||||||
import com.cloud.template.VirtualMachineTemplate;
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
|
import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
@APICommand(name = "listTemplates", description = "List all public, private, and privileged templates.", responseObject = TemplateResponse.class, entityType = {VirtualMachineTemplate.class}, responseView = ResponseView.Restricted,
|
@APICommand(name = "listTemplates", description = "List all public, private, and privileged templates.", responseObject = TemplateResponse.class, entityType = {VirtualMachineTemplate.class}, responseView = ResponseView.Restricted,
|
||||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||||
@ -111,6 +110,11 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
|||||||
since = "4.20")
|
since = "4.20")
|
||||||
private String arch;
|
private String arch;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.OS_CATEGORY_ID, type = CommandType.UUID, entityType= GuestOSCategoryResponse.class,
|
||||||
|
description = "the ID of the OS category for the template",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Long osCategoryId;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -205,6 +209,10 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
|||||||
return CPU.CPUArch.fromType(arch);
|
return CPU.CPUArch.fromType(arch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getOsCategoryId() {
|
||||||
|
return osCategoryId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCommandName() {
|
public String getCommandName() {
|
||||||
return s_name;
|
return s_name;
|
||||||
@ -218,24 +226,14 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
|||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
ListResponse<TemplateResponse> response = _queryService.listTemplates(this);
|
ListResponse<TemplateResponse> response = _queryService.listTemplates(this);
|
||||||
if (response != null && response.getCount() > 0 && getShowIcon()) {
|
if (response != null && getShowIcon()) {
|
||||||
updateTemplateResponse(response.getResponses());
|
_responseGenerator.updateTemplateIsoResponsesForIcons(response.getResponses(),
|
||||||
|
ResourceTag.ResourceObjectType.Template);
|
||||||
}
|
}
|
||||||
response.setResponseName(getCommandName());
|
response.setResponseName(getCommandName());
|
||||||
setResponseObject(response);
|
setResponseObject(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTemplateResponse(List<TemplateResponse> response) {
|
|
||||||
for (TemplateResponse templateResponse : response) {
|
|
||||||
ResourceIcon resourceIcon = resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.Template, templateResponse.getId());
|
|
||||||
if (resourceIcon == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ResourceIconResponse iconResponse = _responseGenerator.createResourceIconResponse(resourceIcon);
|
|
||||||
templateResponse.setResourceIconResponse(iconResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Long> getIds() {
|
public List<Long> getIds() {
|
||||||
if (ids == null) {
|
if (ids == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|||||||
@ -16,10 +16,15 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.command.user.vm;
|
package org.apache.cloudstack.api.command.user.vm;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
||||||
@ -54,6 +59,7 @@ import com.cloud.cpu.CPU;
|
|||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.server.ResourceIcon;
|
import com.cloud.server.ResourceIcon;
|
||||||
import com.cloud.server.ResourceTag;
|
import com.cloud.server.ResourceTag;
|
||||||
|
import com.cloud.storage.GuestOS;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
|
||||||
|
|
||||||
@ -331,22 +337,75 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements
|
|||||||
setResponseObject(response);
|
setResponseObject(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateVMResponse(List<UserVmResponse> response) {
|
protected Map<String, ResourceIcon> getResourceIconsUsingOsCategory(List<UserVmResponse> responses) {
|
||||||
for (UserVmResponse vmResponse : response) {
|
Set<String> guestOsIds = responses.stream().map(UserVmResponse::getGuestOsId).collect(Collectors.toSet());
|
||||||
ResourceIcon resourceIcon = resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.UserVm, vmResponse.getId());
|
List<GuestOS> guestOSList = _entityMgr.listByUuids(GuestOS.class, guestOsIds);
|
||||||
if (resourceIcon == null) {
|
Map<String, GuestOS> guestOSMap = guestOSList.stream()
|
||||||
ResourceTag.ResourceObjectType type = ResourceTag.ResourceObjectType.Template;
|
.collect(Collectors.toMap(GuestOS::getUuid, Function.identity()));
|
||||||
String uuid = vmResponse.getTemplateId();
|
Set<Long> guestOsCategoryIds = guestOSMap.values().stream()
|
||||||
if (vmResponse.getIsoId() != null) {
|
.map(GuestOS::getCategoryId)
|
||||||
uuid = vmResponse.getIsoId();
|
.collect(Collectors.toSet());
|
||||||
type = ResourceTag.ResourceObjectType.ISO;
|
Map<Long, ResourceIcon> guestOsCategoryIcons =
|
||||||
}
|
resourceIconManager.getByResourceTypeAndIds(ResourceTag.ResourceObjectType.GuestOsCategory,
|
||||||
resourceIcon = resourceIconManager.getByResourceTypeAndUuid(type, uuid);
|
guestOsCategoryIds);
|
||||||
if (resourceIcon == null) {
|
Map<String, ResourceIcon> vmIcons = new HashMap<>();
|
||||||
continue;
|
for (UserVmResponse response : responses) {
|
||||||
}
|
GuestOS guestOS = guestOSMap.get(response.getGuestOsId());
|
||||||
|
if (guestOS != null) {
|
||||||
|
vmIcons.put(response.getId(), guestOsCategoryIcons.get(guestOS.getCategoryId()));
|
||||||
}
|
}
|
||||||
ResourceIconResponse iconResponse = _responseGenerator.createResourceIconResponse(resourceIcon);
|
}
|
||||||
|
return vmIcons;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, ResourceIcon> getResourceIconsForUsingTemplateIso(List<UserVmResponse> responses) {
|
||||||
|
Map<String, String> vmTemplateIsoIdMap = new HashMap<>();
|
||||||
|
Set<String> templateUuids = new HashSet<>();
|
||||||
|
Set<String> isoUuids = new HashSet<>();
|
||||||
|
for (UserVmResponse vmResponse : responses) {
|
||||||
|
if (vmResponse.getTemplateId() != null) {
|
||||||
|
templateUuids.add(vmResponse.getTemplateId());
|
||||||
|
vmTemplateIsoIdMap.put(vmResponse.getId(), vmResponse.getTemplateId());
|
||||||
|
}
|
||||||
|
if (vmResponse.getIsoId() != null) {
|
||||||
|
isoUuids.add(vmResponse.getIsoId());
|
||||||
|
vmTemplateIsoIdMap.put(vmResponse.getId(), vmResponse.getIsoId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, ResourceIcon> templateOrIsoIcons = resourceIconManager.getByResourceTypeAndUuids(ResourceTag.ResourceObjectType.Template, templateUuids);
|
||||||
|
templateOrIsoIcons.putAll(resourceIconManager.getByResourceTypeAndUuids(ResourceTag.ResourceObjectType.ISO, isoUuids));
|
||||||
|
Map<String, ResourceIcon> vmIcons = new HashMap<>();
|
||||||
|
List<UserVmResponse> noTemplateIsoIconResponses = new ArrayList<>();
|
||||||
|
for (UserVmResponse response : responses) {
|
||||||
|
String uuid = vmTemplateIsoIdMap.get(response.getId());
|
||||||
|
if (StringUtils.isNotBlank(uuid) && templateOrIsoIcons.containsKey(uuid)) {
|
||||||
|
vmIcons.put(response.getId(),
|
||||||
|
templateOrIsoIcons.get(vmTemplateIsoIdMap.get(response.getId())));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
noTemplateIsoIconResponses.add(response);
|
||||||
|
}
|
||||||
|
vmIcons.putAll(getResourceIconsUsingOsCategory(noTemplateIsoIconResponses));
|
||||||
|
return vmIcons;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateVMResponse(List<UserVmResponse> responses) {
|
||||||
|
if (CollectionUtils.isEmpty(responses)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<String> vmUuids = responses.stream().map(UserVmResponse::getId).collect(Collectors.toSet());
|
||||||
|
Map<String, ResourceIcon> vmIcons = resourceIconManager.getByResourceTypeAndUuids(ResourceTag.ResourceObjectType.UserVm, vmUuids);
|
||||||
|
List<UserVmResponse> noVmIconResponses = responses
|
||||||
|
.stream()
|
||||||
|
.filter(r -> !vmIcons.containsKey(r.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
vmIcons.putAll(getResourceIconsForUsingTemplateIso(noVmIconResponses));
|
||||||
|
for (UserVmResponse vmResponse : responses) {
|
||||||
|
ResourceIcon icon = vmIcons.get(vmResponse.getId());
|
||||||
|
if (icon == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ResourceIconResponse iconResponse = _responseGenerator.createResourceIconResponse(icon);
|
||||||
vmResponse.setResourceIconResponse(iconResponse);
|
vmResponse.setResourceIconResponse(iconResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,8 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.response;
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
@ -26,7 +28,7 @@ import com.cloud.serializer.Param;
|
|||||||
import com.cloud.storage.GuestOsCategory;
|
import com.cloud.storage.GuestOsCategory;
|
||||||
|
|
||||||
@EntityReference(value = GuestOsCategory.class)
|
@EntityReference(value = GuestOsCategory.class)
|
||||||
public class GuestOSCategoryResponse extends BaseResponse {
|
public class GuestOSCategoryResponse extends BaseResponse implements SetResourceIconResponse {
|
||||||
@SerializedName(ApiConstants.ID)
|
@SerializedName(ApiConstants.ID)
|
||||||
@Param(description = "the ID of the OS category")
|
@Param(description = "the ID of the OS category")
|
||||||
private String id;
|
private String id;
|
||||||
@ -35,6 +37,18 @@ public class GuestOSCategoryResponse extends BaseResponse {
|
|||||||
@Param(description = "the name of the OS category")
|
@Param(description = "the name of the OS category")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.IS_FEATURED)
|
||||||
|
@Param(description = "Whether the OS category is featured", since = "4.21.0")
|
||||||
|
private Boolean featured;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.RESOURCE_ICON)
|
||||||
|
@Param(description = "Base64 string representation of the resource icon", since = "4.21.0")
|
||||||
|
private ResourceIconResponse resourceIconResponse;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.CREATED)
|
||||||
|
@Param(description = "Date when the OS category was created." )
|
||||||
|
private Date created;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -50,4 +64,17 @@ public class GuestOSCategoryResponse extends BaseResponse {
|
|||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFeatured(Boolean featured) {
|
||||||
|
this.featured = featured;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResourceIconResponse(ResourceIconResponse resourceIconResponse) {
|
||||||
|
this.resourceIconResponse = resourceIconResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(Date created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,6 +93,8 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
@Param(description = "the name of the OS type for this template.")
|
@Param(description = "the name of the OS type for this template.")
|
||||||
private String osTypeName;
|
private String osTypeName;
|
||||||
|
|
||||||
|
private transient Long osTypeCategoryId;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.ACCOUNT_ID)
|
@SerializedName(ApiConstants.ACCOUNT_ID)
|
||||||
@Param(description = "the account id to which the template belongs")
|
@Param(description = "the account id to which the template belongs")
|
||||||
private String accountId;
|
private String accountId;
|
||||||
@ -285,6 +287,14 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
this.osTypeName = osTypeName;
|
this.osTypeName = osTypeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getOsTypeCategoryId() {
|
||||||
|
return osTypeCategoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOsTypeCategoryId(Long osTypeCategoryId) {
|
||||||
|
this.osTypeCategoryId = osTypeCategoryId;
|
||||||
|
}
|
||||||
|
|
||||||
public void setId(String id) {
|
public void setId(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.api.command.admin.guest;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class AddGuestOsCategoryCmdTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetArch() {
|
||||||
|
AddGuestOsCategoryCmd cmd = new AddGuestOsCategoryCmd();
|
||||||
|
Assert.assertNull(cmd.getName());
|
||||||
|
String name = "Name";
|
||||||
|
ReflectionTestUtils.setField(cmd, "name", name);
|
||||||
|
Assert.assertEquals(name, cmd.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsFeatured() {
|
||||||
|
AddGuestOsCategoryCmd cmd = new AddGuestOsCategoryCmd();
|
||||||
|
Assert.assertFalse(cmd.isFeatured());
|
||||||
|
ReflectionTestUtils.setField(cmd, "featured", false);
|
||||||
|
Assert.assertFalse(cmd.isFeatured());
|
||||||
|
ReflectionTestUtils.setField(cmd, "featured", true);
|
||||||
|
Assert.assertTrue(cmd.isFeatured());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.api.command.admin.guest;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class UpdateGuestOsCategoryCmdTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetArch() {
|
||||||
|
UpdateGuestOsCategoryCmd cmd = new UpdateGuestOsCategoryCmd();
|
||||||
|
Assert.assertNull(cmd.getName());
|
||||||
|
String name = "Name";
|
||||||
|
ReflectionTestUtils.setField(cmd, "name", name);
|
||||||
|
Assert.assertEquals(name, cmd.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsFeatured() {
|
||||||
|
UpdateGuestOsCategoryCmd cmd = new UpdateGuestOsCategoryCmd();
|
||||||
|
Assert.assertNull(cmd.isFeatured());
|
||||||
|
ReflectionTestUtils.setField(cmd, "featured", false);
|
||||||
|
Assert.assertFalse(cmd.isFeatured());
|
||||||
|
ReflectionTestUtils.setField(cmd, "featured", true);
|
||||||
|
Assert.assertTrue(cmd.isFeatured());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSortKey() {
|
||||||
|
UpdateGuestOsCategoryCmd cmd = new UpdateGuestOsCategoryCmd();
|
||||||
|
Assert.assertNull(cmd.getSortKey());
|
||||||
|
Integer sortKey = 100;
|
||||||
|
ReflectionTestUtils.setField(cmd, "sortKey", sortKey);
|
||||||
|
Assert.assertEquals(sortKey, cmd.getSortKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.api.command.admin.guest;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class UpdateGuestOsCmdTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetZoneId() {
|
||||||
|
UpdateGuestOsCmd cmd = new UpdateGuestOsCmd();
|
||||||
|
Assert.assertNull(cmd.getOsCategoryId());
|
||||||
|
Long osCategoryId = 100L;
|
||||||
|
ReflectionTestUtils.setField(cmd, "osCategoryId", osCategoryId);
|
||||||
|
Assert.assertEquals(osCategoryId, cmd.getOsCategoryId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.api.command.user.guest;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import com.cloud.cpu.CPU;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class ListGuestOsCategoriesCmdTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsFeatured() {
|
||||||
|
ListGuestOsCategoriesCmd cmd = new ListGuestOsCategoriesCmd();
|
||||||
|
Assert.assertNull(cmd.isFeatured());
|
||||||
|
ReflectionTestUtils.setField(cmd, "featured", false);
|
||||||
|
Assert.assertFalse(cmd.isFeatured());
|
||||||
|
ReflectionTestUtils.setField(cmd, "featured", true);
|
||||||
|
Assert.assertTrue(cmd.isFeatured());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsIso() {
|
||||||
|
ListGuestOsCategoriesCmd cmd = new ListGuestOsCategoriesCmd();
|
||||||
|
Assert.assertNull(cmd.isIso());
|
||||||
|
ReflectionTestUtils.setField(cmd, "iso", false);
|
||||||
|
Assert.assertFalse(cmd.isIso());
|
||||||
|
ReflectionTestUtils.setField(cmd, "iso", true);
|
||||||
|
Assert.assertTrue(cmd.isIso());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsVnf() {
|
||||||
|
ListGuestOsCategoriesCmd cmd = new ListGuestOsCategoriesCmd();
|
||||||
|
Assert.assertNull(cmd.isVnf());
|
||||||
|
ReflectionTestUtils.setField(cmd, "vnf", false);
|
||||||
|
Assert.assertFalse(cmd.isVnf());
|
||||||
|
ReflectionTestUtils.setField(cmd, "vnf", true);
|
||||||
|
Assert.assertTrue(cmd.isVnf());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetZoneId() {
|
||||||
|
ListGuestOsCategoriesCmd cmd = new ListGuestOsCategoriesCmd();
|
||||||
|
Assert.assertNull(cmd.getZoneId());
|
||||||
|
Long zoneId = 100L;
|
||||||
|
ReflectionTestUtils.setField(cmd, "zoneId", zoneId);
|
||||||
|
Assert.assertEquals(zoneId, cmd.getZoneId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetArch() {
|
||||||
|
ListGuestOsCategoriesCmd cmd = new ListGuestOsCategoriesCmd();
|
||||||
|
Assert.assertNull(cmd.getArch());
|
||||||
|
CPU.CPUArch arch = CPU.CPUArch.getDefault();
|
||||||
|
ReflectionTestUtils.setField(cmd, "arch", arch.getType());
|
||||||
|
Assert.assertEquals(arch, cmd.getArch());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsShowIcon() {
|
||||||
|
ListGuestOsCategoriesCmd cmd = new ListGuestOsCategoriesCmd();
|
||||||
|
Assert.assertFalse(cmd.isShowIcon());
|
||||||
|
ReflectionTestUtils.setField(cmd, "showIcon", false);
|
||||||
|
Assert.assertFalse(cmd.isShowIcon());
|
||||||
|
ReflectionTestUtils.setField(cmd, "showIcon", true);
|
||||||
|
Assert.assertTrue(cmd.isShowIcon());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,223 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.api.command.user.vm;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.anyList;
|
||||||
|
import static org.mockito.Mockito.anySet;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ResponseGenerator;
|
||||||
|
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
||||||
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import com.cloud.server.ResourceIcon;
|
||||||
|
import com.cloud.server.ResourceIconManager;
|
||||||
|
import com.cloud.server.ResourceTag;
|
||||||
|
import com.cloud.storage.GuestOS;
|
||||||
|
import com.cloud.utils.db.EntityManager;
|
||||||
|
|
||||||
|
public class ListVMsCmdTest {
|
||||||
|
|
||||||
|
EntityManager _entityMgr;
|
||||||
|
ResourceIconManager resourceIconManager;
|
||||||
|
ResponseGenerator _responseGenerator;
|
||||||
|
|
||||||
|
ListVMsCmd cmd;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
_entityMgr = mock(EntityManager.class);
|
||||||
|
resourceIconManager = mock(ResourceIconManager.class);
|
||||||
|
_responseGenerator = mock(ResponseGenerator.class);
|
||||||
|
cmd = spy(ListVMsCmd.class);
|
||||||
|
cmd._entityMgr = _entityMgr;
|
||||||
|
cmd.resourceIconManager = resourceIconManager;
|
||||||
|
cmd._responseGenerator = _responseGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateVMResponse_withMixedIcons() {
|
||||||
|
String vm1Uuid = UUID.randomUUID().toString();
|
||||||
|
UserVmResponse vm1 = mock(UserVmResponse.class);
|
||||||
|
when(vm1.getId()).thenReturn(vm1Uuid);
|
||||||
|
String vm2Uuid = UUID.randomUUID().toString();
|
||||||
|
UserVmResponse vm2 = mock(UserVmResponse.class);
|
||||||
|
when(vm2.getId()).thenReturn(vm2Uuid);
|
||||||
|
List<UserVmResponse> responses = Arrays.asList(vm1, vm2);
|
||||||
|
ResourceIcon icon1 = mock(ResourceIcon.class);
|
||||||
|
ResourceIcon icon2 = mock(ResourceIcon.class);
|
||||||
|
Map<String, ResourceIcon> initialIcons = new HashMap<>();
|
||||||
|
initialIcons.put(vm1Uuid, icon1);
|
||||||
|
when(resourceIconManager.getByResourceTypeAndUuids(ResourceTag.ResourceObjectType.UserVm, Set.of(vm1Uuid, vm2Uuid)))
|
||||||
|
.thenReturn(initialIcons);
|
||||||
|
Map<String, ResourceIcon> fallbackIcons = Map.of(vm2Uuid, icon2);
|
||||||
|
doReturn(fallbackIcons).when(cmd).getResourceIconsForUsingTemplateIso(anyList());
|
||||||
|
ResourceIconResponse iconResponse1 = new ResourceIconResponse();
|
||||||
|
ResourceIconResponse iconResponse2 = new ResourceIconResponse();
|
||||||
|
when(_responseGenerator.createResourceIconResponse(icon1)).thenReturn(iconResponse1);
|
||||||
|
when(_responseGenerator.createResourceIconResponse(icon2)).thenReturn(iconResponse2);
|
||||||
|
cmd.updateVMResponse(responses);
|
||||||
|
verify(vm1).setResourceIconResponse(iconResponse1);
|
||||||
|
verify(vm2).setResourceIconResponse(iconResponse2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateVMResponse_withEmptyList() {
|
||||||
|
cmd.updateVMResponse(Collections.emptyList());
|
||||||
|
verify(resourceIconManager, never()).getByResourceTypeAndIds(Mockito.any(), Mockito.anyCollection());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResourceIconsForUsingTemplateIso_withValidData() {
|
||||||
|
String vm1Uuid = UUID.randomUUID().toString();
|
||||||
|
String template1Uuid = UUID.randomUUID().toString();
|
||||||
|
UserVmResponse vm1 = mock(UserVmResponse.class);
|
||||||
|
when(vm1.getId()).thenReturn(vm1Uuid);
|
||||||
|
when(vm1.getTemplateId()).thenReturn(template1Uuid);
|
||||||
|
when(vm1.getIsoId()).thenReturn(null);
|
||||||
|
String vm2Uuid = UUID.randomUUID().toString();
|
||||||
|
String iso2Uuid = UUID.randomUUID().toString();
|
||||||
|
UserVmResponse vm2 = mock(UserVmResponse.class);
|
||||||
|
when(vm2.getId()).thenReturn(vm2Uuid);
|
||||||
|
when(vm2.getTemplateId()).thenReturn(null);
|
||||||
|
when(vm2.getIsoId()).thenReturn(iso2Uuid);
|
||||||
|
List<UserVmResponse> responses = Arrays.asList(vm1, vm2);
|
||||||
|
Map<String, ResourceIcon> templateIcons = new HashMap<>();
|
||||||
|
templateIcons.put(template1Uuid, mock(ResourceIcon.class));
|
||||||
|
Map<String, ResourceIcon> isoIcons = new HashMap<>();
|
||||||
|
isoIcons.put(iso2Uuid, mock(ResourceIcon.class));
|
||||||
|
when(resourceIconManager.getByResourceTypeAndUuids(ResourceTag.ResourceObjectType.Template, Set.of(template1Uuid)))
|
||||||
|
.thenReturn(templateIcons);
|
||||||
|
when(resourceIconManager.getByResourceTypeAndUuids(ResourceTag.ResourceObjectType.ISO, Set.of(iso2Uuid)))
|
||||||
|
.thenReturn(isoIcons);
|
||||||
|
doReturn(Collections.emptyMap()).when(cmd).getResourceIconsUsingOsCategory(anyList());
|
||||||
|
Map<String, ResourceIcon> result = cmd.getResourceIconsForUsingTemplateIso(responses);
|
||||||
|
assertEquals(2, result.size());
|
||||||
|
assertTrue(result.containsKey(vm1Uuid));
|
||||||
|
assertTrue(result.containsKey(vm2Uuid));
|
||||||
|
assertEquals(templateIcons.get(template1Uuid), result.get(vm1Uuid));
|
||||||
|
assertEquals(isoIcons.get(iso2Uuid), result.get(vm2Uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResourceIconsForUsingTemplateIso_withMissingIcons() {
|
||||||
|
String vm1Uuid = UUID.randomUUID().toString();
|
||||||
|
String template1Uuid = UUID.randomUUID().toString();
|
||||||
|
UserVmResponse vm1 = mock(UserVmResponse.class);
|
||||||
|
when(vm1.getId()).thenReturn(vm1Uuid);
|
||||||
|
when(vm1.getTemplateId()).thenReturn(template1Uuid);
|
||||||
|
when(vm1.getIsoId()).thenReturn(null);
|
||||||
|
List<UserVmResponse> responses = List.of(vm1);
|
||||||
|
when(resourceIconManager.getByResourceTypeAndUuids(eq(ResourceTag.ResourceObjectType.Template), anySet()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
when(resourceIconManager.getByResourceTypeAndUuids(eq(ResourceTag.ResourceObjectType.ISO), anySet()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
Map<String, ResourceIcon> fallbackIcons = Map.of(vm1Uuid, mock(ResourceIcon.class));
|
||||||
|
doReturn(fallbackIcons).when(cmd).getResourceIconsUsingOsCategory(anyList());
|
||||||
|
Map<String, ResourceIcon> result = cmd.getResourceIconsForUsingTemplateIso(responses);
|
||||||
|
assertEquals(1, result.size());
|
||||||
|
assertEquals(fallbackIcons.get("vm1"), result.get("vm1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResourceIconsUsingOsCategory_withValidData() {
|
||||||
|
String vm1Uuid = UUID.randomUUID().toString();
|
||||||
|
String os1Uuid = UUID.randomUUID().toString();
|
||||||
|
UserVmResponse vm1 = mock(UserVmResponse.class);
|
||||||
|
when(vm1.getGuestOsId()).thenReturn(os1Uuid);
|
||||||
|
when(vm1.getId()).thenReturn(vm1Uuid);
|
||||||
|
String vm2Uuid = UUID.randomUUID().toString();
|
||||||
|
String os2Uuid = UUID.randomUUID().toString();
|
||||||
|
UserVmResponse vm2 = mock(UserVmResponse.class);
|
||||||
|
when(vm2.getGuestOsId()).thenReturn(os2Uuid);
|
||||||
|
when(vm2.getId()).thenReturn(vm2Uuid);
|
||||||
|
List<UserVmResponse> responses = Arrays.asList(vm1, vm2);
|
||||||
|
GuestOS guestOS1 = mock(GuestOS.class);
|
||||||
|
when(guestOS1.getUuid()).thenReturn(os1Uuid);
|
||||||
|
when(guestOS1.getCategoryId()).thenReturn(10L);
|
||||||
|
GuestOS guestOS2 = mock(GuestOS.class);
|
||||||
|
when(guestOS2.getUuid()).thenReturn(os2Uuid);
|
||||||
|
when(guestOS2.getCategoryId()).thenReturn(20L);
|
||||||
|
when(_entityMgr.listByUuids(eq(GuestOS.class), anySet()))
|
||||||
|
.thenReturn(Arrays.asList(guestOS1, guestOS2));
|
||||||
|
ResourceIcon icon1 = mock(ResourceIcon.class);
|
||||||
|
ResourceIcon icon2 = mock(ResourceIcon.class);
|
||||||
|
Map<Long, ResourceIcon> categoryIcons = new HashMap<>();
|
||||||
|
categoryIcons.put(10L, icon1);
|
||||||
|
categoryIcons.put(20L, icon2);
|
||||||
|
when(resourceIconManager.getByResourceTypeAndIds(eq(ResourceTag.ResourceObjectType.GuestOsCategory), anySet()))
|
||||||
|
.thenReturn(categoryIcons);
|
||||||
|
Map<String, ResourceIcon> result = cmd.getResourceIconsUsingOsCategory(responses);
|
||||||
|
assertEquals(2, result.size());
|
||||||
|
assertEquals(icon1, result.get(vm1Uuid));
|
||||||
|
assertEquals(icon2, result.get(vm2Uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResourceIconsUsingOsCategory_missingGuestOS() {
|
||||||
|
String vm1Uuid = UUID.randomUUID().toString();
|
||||||
|
String os1Uuid = UUID.randomUUID().toString();
|
||||||
|
UserVmResponse vm1 = mock(UserVmResponse.class);
|
||||||
|
when(vm1.getGuestOsId()).thenReturn(vm1Uuid);
|
||||||
|
when(vm1.getId()).thenReturn(os1Uuid);
|
||||||
|
List<UserVmResponse> responses = Collections.singletonList(vm1);
|
||||||
|
when(_entityMgr.listByUuids(eq(GuestOS.class), anySet()))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
Map<String, ResourceIcon> result = cmd.getResourceIconsUsingOsCategory(responses);
|
||||||
|
assertTrue(result.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResourceIconsUsingOsCategory_missingIcon() {
|
||||||
|
UserVmResponse vm1 = mock(UserVmResponse.class);
|
||||||
|
String vmUuid = UUID.randomUUID().toString();
|
||||||
|
String osUuid = UUID.randomUUID().toString();
|
||||||
|
when(vm1.getGuestOsId()).thenReturn(osUuid);
|
||||||
|
when(vm1.getId()).thenReturn(vmUuid);
|
||||||
|
List<UserVmResponse> responses = Collections.singletonList(vm1);
|
||||||
|
GuestOS guestOS1 = mock(GuestOS.class);
|
||||||
|
when(guestOS1.getCategoryId()).thenReturn(10L);
|
||||||
|
when(guestOS1.getUuid()).thenReturn(osUuid);
|
||||||
|
when(_entityMgr.listByUuids(eq(GuestOS.class), anySet()))
|
||||||
|
.thenReturn(Collections.singletonList(guestOS1));
|
||||||
|
when(resourceIconManager.getByResourceTypeAndIds(eq(ResourceTag.ResourceObjectType.GuestOsCategory), anySet()))
|
||||||
|
.thenReturn(Collections.emptyMap());
|
||||||
|
Map<String, ResourceIcon> result = cmd.getResourceIconsUsingOsCategory(responses);
|
||||||
|
assertTrue(result.containsKey(vmUuid));
|
||||||
|
assertNull(result.get(vmUuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -22,10 +22,13 @@ import com.cloud.server.ResourceTag;
|
|||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface ResourceIconDao extends GenericDao<ResourceIconVO, Long> {
|
public interface ResourceIconDao extends GenericDao<ResourceIconVO, Long> {
|
||||||
ResourceIconResponse newResourceIconResponse(ResourceIcon resourceIconVO);
|
ResourceIconResponse newResourceIconResponse(ResourceIcon resourceIconVO);
|
||||||
ResourceIconVO findByResourceUuid(String resourceUuid, ResourceTag.ResourceObjectType resourceType);
|
ResourceIconVO findByResourceUuid(String resourceUuid, ResourceTag.ResourceObjectType resourceType);
|
||||||
|
List<ResourceIconVO> listByResourceTypeAndIds(ResourceTag.ResourceObjectType resourceType, Collection<Long> resourceIds);
|
||||||
|
List<ResourceIconVO> listByResourceTypeAndUuids(ResourceTag.ResourceObjectType resourceType, Collection<String> resourceUuids);
|
||||||
List<ResourceIconResponse> listResourceIcons(List<String> resourceUuids, ResourceTag.ResourceObjectType resourceType);
|
List<ResourceIconResponse> listResourceIcons(List<String> resourceUuids, ResourceTag.ResourceObjectType resourceType);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,8 +24,10 @@ import com.cloud.utils.db.SearchBuilder;
|
|||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ResourceIconDaoImpl extends GenericDaoBase<ResourceIconVO, Long> implements ResourceIconDao {
|
public class ResourceIconDaoImpl extends GenericDaoBase<ResourceIconVO, Long> implements ResourceIconDao {
|
||||||
@ -58,11 +60,36 @@ public class ResourceIconDaoImpl extends GenericDaoBase<ResourceIconVO, Long> im
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ResourceIconResponse> listResourceIcons(List<String> resourceUuids, ResourceTag.ResourceObjectType resourceType) {
|
public List<ResourceIconVO> listByResourceTypeAndIds(ResourceTag.ResourceObjectType resourceType,
|
||||||
|
Collection<Long> resourceIds) {
|
||||||
|
if (CollectionUtils.isEmpty(resourceIds)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
SearchBuilder<ResourceIconVO> sb = createSearchBuilder();
|
||||||
|
sb.and("resourceId", sb.entity().getResourceId(), SearchCriteria.Op.IN);
|
||||||
|
sb.and("resourceType", sb.entity().getResourceType(), SearchCriteria.Op.EQ);
|
||||||
|
sb.done();
|
||||||
|
SearchCriteria<ResourceIconVO> sc = sb.create();
|
||||||
|
sc.setParameters("resourceId", resourceIds.toArray());
|
||||||
|
sc.setParameters("resourceType", resourceType);
|
||||||
|
return listBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourceIconVO> listByResourceTypeAndUuids(ResourceTag.ResourceObjectType resourceType,
|
||||||
|
Collection<String> resourceUuids) {
|
||||||
|
if (CollectionUtils.isEmpty(resourceUuids)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
SearchCriteria<ResourceIconVO> sc = AllFieldsSearch.create();
|
SearchCriteria<ResourceIconVO> sc = AllFieldsSearch.create();
|
||||||
sc.setParameters("uuid", resourceUuids.toArray());
|
sc.setParameters("uuid", resourceUuids.toArray());
|
||||||
sc.setParameters("resourceType", resourceType);
|
sc.setParameters("resourceType", resourceType);
|
||||||
List<ResourceIconVO> resourceIcons = listBy(sc);
|
return listBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourceIconResponse> listResourceIcons(List<String> resourceUuids, ResourceTag.ResourceObjectType resourceType) {
|
||||||
|
List<ResourceIconVO> resourceIcons = listByResourceTypeAndUuids(resourceType, resourceUuids);
|
||||||
List<ResourceIconResponse> iconResponses = new ArrayList<>();
|
List<ResourceIconResponse> iconResponses = new ArrayList<>();
|
||||||
for (ResourceIconVO resourceIcon : resourceIcons) {
|
for (ResourceIconVO resourceIcon : resourceIcons) {
|
||||||
ResourceIconResponse response = new ResourceIconResponse();
|
ResourceIconResponse response = new ResourceIconResponse();
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.storage;
|
package com.cloud.storage;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
@ -25,6 +26,8 @@ import javax.persistence.GenerationType;
|
|||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "guest_os_category")
|
@Table(name = "guest_os_category")
|
||||||
public class GuestOSCategoryVO implements GuestOsCategory {
|
public class GuestOSCategoryVO implements GuestOsCategory {
|
||||||
@ -39,6 +42,26 @@ public class GuestOSCategoryVO implements GuestOsCategory {
|
|||||||
@Column(name = "uuid")
|
@Column(name = "uuid")
|
||||||
String uuid = UUID.randomUUID().toString();
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@Column(name = "featured")
|
||||||
|
boolean featured;
|
||||||
|
|
||||||
|
@Column(name = "sort_key")
|
||||||
|
private int sortKey;
|
||||||
|
|
||||||
|
@Column(name = GenericDao.CREATED_COLUMN)
|
||||||
|
private Date created;
|
||||||
|
|
||||||
|
@Column(name = GenericDao.REMOVED_COLUMN)
|
||||||
|
private Date removed;
|
||||||
|
|
||||||
|
public GuestOSCategoryVO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuestOSCategoryVO(String name, boolean featured) {
|
||||||
|
this.name = name;
|
||||||
|
this.featured = featured;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
@ -59,7 +82,25 @@ public class GuestOSCategoryVO implements GuestOsCategory {
|
|||||||
return this.uuid;
|
return this.uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUuid(String uuid) {
|
@Override
|
||||||
this.uuid = uuid;
|
public boolean isFeatured() {
|
||||||
|
return featured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFeatured(Boolean featured) {
|
||||||
|
this.featured = featured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortKey(int key) {
|
||||||
|
sortKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSortKey() {
|
||||||
|
return sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getCreated() {
|
||||||
|
return created;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,6 @@ import com.cloud.utils.db.GenericDaoBase;
|
|||||||
public class GuestOSCategoryDaoImpl extends GenericDaoBase<GuestOSCategoryVO, Long> implements GuestOSCategoryDao {
|
public class GuestOSCategoryDaoImpl extends GenericDaoBase<GuestOSCategoryVO, Long> implements GuestOSCategoryDao {
|
||||||
|
|
||||||
protected GuestOSCategoryDaoImpl() {
|
protected GuestOSCategoryDaoImpl() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -16,14 +16,14 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.storage.dao;
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.cloud.storage.GuestOS;
|
import com.cloud.storage.GuestOS;
|
||||||
import com.cloud.storage.GuestOSVO;
|
import com.cloud.storage.GuestOSVO;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface GuestOSDao extends GenericDao<GuestOSVO, Long> {
|
public interface GuestOSDao extends GenericDao<GuestOSVO, Long> {
|
||||||
|
|
||||||
GuestOSVO findOneByDisplayName(String displayName);
|
GuestOSVO findOneByDisplayName(String displayName);
|
||||||
@ -36,4 +36,6 @@ public interface GuestOSDao extends GenericDao<GuestOSVO, Long> {
|
|||||||
List<GuestOSVO> listByDisplayName(String displayName);
|
List<GuestOSVO> listByDisplayName(String displayName);
|
||||||
|
|
||||||
Pair<List<? extends GuestOS>, Integer> listGuestOSByCriteria(Long startIndex, Long pageSize, Long id, Long osCategoryId, String description, String keyword, Boolean forDisplay);
|
Pair<List<? extends GuestOS>, Integer> listGuestOSByCriteria(Long startIndex, Long pageSize, Long id, Long osCategoryId, String description, String keyword, Boolean forDisplay);
|
||||||
|
|
||||||
|
List<Long> listIdsByCategoryId(final long categoryId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,19 +25,20 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.cloud.storage.GuestOS;
|
|
||||||
import com.cloud.utils.Pair;
|
|
||||||
import com.cloud.utils.db.DB;
|
|
||||||
import com.cloud.utils.db.TransactionLegacy;
|
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.cloud.storage.GuestOS;
|
||||||
import com.cloud.storage.GuestOSVO;
|
import com.cloud.storage.GuestOSVO;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.db.DB;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
import com.cloud.utils.db.GenericDaoBase;
|
import com.cloud.utils.db.GenericDaoBase;
|
||||||
|
import com.cloud.utils.db.GenericSearchBuilder;
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import com.cloud.utils.db.TransactionLegacy;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class GuestOSDaoImpl extends GenericDaoBase<GuestOSVO, Long> implements GuestOSDao {
|
public class GuestOSDaoImpl extends GenericDaoBase<GuestOSVO, Long> implements GuestOSDao {
|
||||||
@ -152,4 +153,14 @@ public class GuestOSDaoImpl extends GenericDaoBase<GuestOSVO, Long> implements G
|
|||||||
return new Pair<>(result.first(), result.second());
|
return new Pair<>(result.first(), result.second());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> listIdsByCategoryId(final long categoryId) {
|
||||||
|
GenericSearchBuilder<GuestOSVO, Long> sb = createSearchBuilder(Long.class);
|
||||||
|
sb.selectFields(sb.entity().getId());
|
||||||
|
sb.and("categoryId", sb.entity().getCategoryId(), SearchCriteria.Op.EQ);
|
||||||
|
sb.done();
|
||||||
|
SearchCriteria<Long> sc = sb.create();
|
||||||
|
sc.setParameters("categoryId", categoryId);
|
||||||
|
return customSearch(sc, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,8 @@ public interface VMTemplateDao extends GenericDao<VMTemplateVO, Long>, StateDao<
|
|||||||
|
|
||||||
public List<VMTemplateVO> listInZoneByState(long dataCenterId, VirtualMachineTemplate.State... states);
|
public List<VMTemplateVO> listInZoneByState(long dataCenterId, VirtualMachineTemplate.State... states);
|
||||||
|
|
||||||
|
public List<Long> listTemplateIsoByArchVnfAndZone(Long dataCenterId, CPU.CPUArch arch, Boolean isIso, Boolean isVnf);
|
||||||
|
|
||||||
public List<VMTemplateVO> listAllActive();
|
public List<VMTemplateVO> listAllActive();
|
||||||
|
|
||||||
public List<VMTemplateVO> listByState(VirtualMachineTemplate.State... states);
|
public List<VMTemplateVO> listByState(VirtualMachineTemplate.State... states);
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package com.cloud.storage.dao;
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -520,6 +521,48 @@ public class VMTemplateDaoImpl extends GenericDaoBase<VMTemplateVO, Long> implem
|
|||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> listTemplateIsoByArchVnfAndZone(Long dataCenterId, CPU.CPUArch arch, Boolean isIso,
|
||||||
|
Boolean isVnf) {
|
||||||
|
GenericSearchBuilder<VMTemplateVO, Long> sb = createSearchBuilder(Long.class);
|
||||||
|
sb.select(null, Func.DISTINCT, sb.entity().getGuestOSId());
|
||||||
|
sb.and("state", sb.entity().getState(), SearchCriteria.Op.IN);
|
||||||
|
sb.and("type", sb.entity().getTemplateType(), SearchCriteria.Op.IN);
|
||||||
|
sb.and("arch", sb.entity().getArch(), SearchCriteria.Op.EQ);
|
||||||
|
if (isIso != null) {
|
||||||
|
sb.and("isIso", sb.entity().getFormat(), isIso ? SearchCriteria.Op.EQ : SearchCriteria.Op.NEQ);
|
||||||
|
}
|
||||||
|
if (dataCenterId != null) {
|
||||||
|
SearchBuilder<VMTemplateZoneVO> templateZoneSearch = _templateZoneDao.createSearchBuilder();
|
||||||
|
templateZoneSearch.and("removed", templateZoneSearch.entity().getRemoved(), SearchCriteria.Op.NULL);
|
||||||
|
templateZoneSearch.and("zoneId", templateZoneSearch.entity().getZoneId(), SearchCriteria.Op.EQ);
|
||||||
|
sb.join("templateZoneSearch", templateZoneSearch, templateZoneSearch.entity().getTemplateId(),
|
||||||
|
sb.entity().getId(), JoinBuilder.JoinType.INNER);
|
||||||
|
templateZoneSearch.done();
|
||||||
|
}
|
||||||
|
sb.done();
|
||||||
|
SearchCriteria<Long> sc = sb.create();
|
||||||
|
List<TemplateType> types = new ArrayList<>(Arrays.asList(TemplateType.USER, TemplateType.BUILTIN,
|
||||||
|
TemplateType.PERHOST));
|
||||||
|
if (isVnf == null) {
|
||||||
|
types.add(TemplateType.VNF);
|
||||||
|
} else if (isVnf) {
|
||||||
|
types = Collections.singletonList(TemplateType.VNF);
|
||||||
|
}
|
||||||
|
sc.setParameters("type", types.toArray());
|
||||||
|
sc.setParameters("state", VirtualMachineTemplate.State.Active);
|
||||||
|
if (dataCenterId != null) {
|
||||||
|
sc.setJoinParameters("templateZoneSearch", "zoneId", dataCenterId);
|
||||||
|
}
|
||||||
|
if (arch != null) {
|
||||||
|
sc.setParameters("arch", arch);
|
||||||
|
}
|
||||||
|
if (isIso != null) {
|
||||||
|
sc.setParameters("isIso", ImageFormat.ISO);
|
||||||
|
}
|
||||||
|
return customSearch(sc, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VMTemplateVO> listAllActive() {
|
public List<VMTemplateVO> listAllActive() {
|
||||||
SearchCriteria<VMTemplateVO> sc = ActiveTmpltSearch.create();
|
SearchCriteria<VMTemplateVO> sc = ActiveTmpltSearch.create();
|
||||||
|
|||||||
@ -80,3 +80,93 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.host', 'storage_access_groups', 'var
|
|||||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.cluster', 'storage_access_groups', 'varchar(255) DEFAULT NULL COMMENT "storage access groups for the hosts in the cluster"');
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.cluster', 'storage_access_groups', 'varchar(255) DEFAULT NULL COMMENT "storage access groups for the hosts in the cluster"');
|
||||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.host_pod_ref', 'storage_access_groups', 'varchar(255) DEFAULT NULL COMMENT "storage access groups for the hosts in the pod"');
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.host_pod_ref', 'storage_access_groups', 'varchar(255) DEFAULT NULL COMMENT "storage access groups for the hosts in the pod"');
|
||||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.data_center', 'storage_access_groups', 'varchar(255) DEFAULT NULL COMMENT "storage access groups for the hosts in the zone"');
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.data_center', 'storage_access_groups', 'varchar(255) DEFAULT NULL COMMENT "storage access groups for the hosts in the zone"');
|
||||||
|
|
||||||
|
-- Add featured column for guest_os_category
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.guest_os_category', 'featured', 'tinyint(1) NOT NULL DEFAULT 0 COMMENT "whether the category is featured or not" AFTER `uuid`');
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.guest_os_category', 'sort_key', 'int NOT NULL DEFAULT 0 COMMENT "sort key used for customising sort method" AFTER `featured`');
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.guest_os_category', 'created', 'datetime COMMENT "date on which the category was created" AFTER `sort_key`');
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.guest_os_category', 'removed', 'datetime COMMENT "date removed if not null" AFTER `created`');
|
||||||
|
UPDATE `cloud`.`guest_os_category` SET `featured` = 1 WHERE `name` NOT IN ('Novel', 'None');
|
||||||
|
|
||||||
|
-- Begin: Changes for Guest OS category cleanup
|
||||||
|
-- Add new OS categories if not present
|
||||||
|
DROP PROCEDURE IF EXISTS `cloud`.`INSERT_CATEGORY_IF_NOT_EXIST`;
|
||||||
|
CREATE PROCEDURE `cloud`.`INSERT_CATEGORY_IF_NOT_EXIST`(IN os_name VARCHAR(255))
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS ((SELECT 1 FROM `cloud`.`guest_os_category` WHERE name = os_name))
|
||||||
|
THEN
|
||||||
|
INSERT INTO `cloud`.`guest_os_category` (name, uuid)
|
||||||
|
VALUES (os_name, UUID())
|
||||||
|
; END IF
|
||||||
|
; END;
|
||||||
|
|
||||||
|
CALL `cloud`.`INSERT_CATEGORY_IF_NOT_EXIST`('Fedora');
|
||||||
|
CALL `cloud`.`INSERT_CATEGORY_IF_NOT_EXIST`('Rocky Linux');
|
||||||
|
CALL `cloud`.`INSERT_CATEGORY_IF_NOT_EXIST`('Alma Linux');
|
||||||
|
|
||||||
|
-- Move existing guest OS to new categories
|
||||||
|
DROP PROCEDURE IF EXISTS `cloud`.`UPDATE_CATEGORY_FOR_GUEST_OSES`;
|
||||||
|
CREATE PROCEDURE `cloud`.`UPDATE_CATEGORY_FOR_GUEST_OSES`(IN category_name VARCHAR(255), IN os_name VARCHAR(255))
|
||||||
|
BEGIN
|
||||||
|
DECLARE category_id BIGINT
|
||||||
|
; SELECT `id` INTO category_id
|
||||||
|
FROM `cloud`.`guest_os_category`
|
||||||
|
WHERE `name` = category_name
|
||||||
|
LIMIT 1
|
||||||
|
; IF category_id IS NULL THEN
|
||||||
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Category not found'
|
||||||
|
; END IF
|
||||||
|
; UPDATE `cloud`.`guest_os`
|
||||||
|
SET `category_id` = category_id
|
||||||
|
WHERE `display_name` LIKE CONCAT('%', os_name, '%')
|
||||||
|
; END;
|
||||||
|
CALL `cloud`.`UPDATE_CATEGORY_FOR_GUEST_OSES`('Rocky Linux', 'Rocky Linux');
|
||||||
|
CALL `cloud`.`UPDATE_CATEGORY_FOR_GUEST_OSES`('Alma Linux', 'Alma Linux');
|
||||||
|
CALL `cloud`.`UPDATE_CATEGORY_FOR_GUEST_OSES`('Fedora', 'Fedora');
|
||||||
|
|
||||||
|
-- Move existing guest OS whose category will be deleted to Other category
|
||||||
|
DROP PROCEDURE IF EXISTS `cloud`.`UPDATE_NEW_AND_DELETE_OLD_CATEGORY_FOR_GUEST_OS`;
|
||||||
|
CREATE PROCEDURE `cloud`.`UPDATE_NEW_AND_DELETE_OLD_CATEGORY_FOR_GUEST_OS`(IN to_category_name VARCHAR(255), IN from_category_name VARCHAR(255))
|
||||||
|
BEGIN
|
||||||
|
DECLARE done INT DEFAULT 0
|
||||||
|
; DECLARE to_category_id BIGINT
|
||||||
|
; SELECT id INTO to_category_id
|
||||||
|
FROM `cloud`.`guest_os_category`
|
||||||
|
WHERE `name` = to_category_name
|
||||||
|
LIMIT 1
|
||||||
|
; IF to_category_id IS NULL THEN
|
||||||
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'ToCategory not found'
|
||||||
|
; END IF
|
||||||
|
; UPDATE `cloud`.`guest_os`
|
||||||
|
SET `category_id` = to_category_id
|
||||||
|
WHERE `category_id` = (SELECT `id` FROM `cloud`.`guest_os_category` WHERE `name` = from_category_name)
|
||||||
|
; UPDATE `cloud`.`guest_os_category` SET `removed`=now() WHERE `name` = from_category_name
|
||||||
|
; END;
|
||||||
|
CALL `cloud`.`UPDATE_NEW_AND_DELETE_OLD_CATEGORY_FOR_GUEST_OS`('Other', 'Novel');
|
||||||
|
CALL `cloud`.`UPDATE_NEW_AND_DELETE_OLD_CATEGORY_FOR_GUEST_OS`('Other', 'None');
|
||||||
|
CALL `cloud`.`UPDATE_NEW_AND_DELETE_OLD_CATEGORY_FOR_GUEST_OS`('Other', 'Unix');
|
||||||
|
CALL `cloud`.`UPDATE_NEW_AND_DELETE_OLD_CATEGORY_FOR_GUEST_OS`('Other', 'Mac');
|
||||||
|
|
||||||
|
-- Add featured column for cloud.guest_os_category
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.guest_os_category', 'featured', 'tinyint(1) NOT NULL DEFAULT 0 COMMENT "whether the category is featured or not" AFTER `uuid`');
|
||||||
|
UPDATE `cloud`.`guest_os_category` SET featured = 1;
|
||||||
|
-- Add sort_key column for cloud.guest_os_category
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.guest_os_category', 'sort_key', 'int NOT NULL DEFAULT 0 COMMENT "sort key used for customising sort method" AFTER `featured`');
|
||||||
|
|
||||||
|
-- Update sort order for all guest OS categories
|
||||||
|
UPDATE `cloud`.`guest_os_category`
|
||||||
|
SET `sort_key` = CASE
|
||||||
|
WHEN `name` = 'Ubuntu' THEN 1
|
||||||
|
WHEN `name` = 'Debian' THEN 2
|
||||||
|
WHEN `name` = 'Fedora' THEN 3
|
||||||
|
WHEN `name` = 'CentOS' THEN 4
|
||||||
|
WHEN `name` = 'Rocky Linux' THEN 5
|
||||||
|
WHEN `name` = 'Alma Linux' THEN 6
|
||||||
|
WHEN `name` = 'Oracle' THEN 7
|
||||||
|
WHEN `name` = 'RedHat' THEN 8
|
||||||
|
WHEN `name` = 'SUSE' THEN 9
|
||||||
|
WHEN `name` = 'Windows' THEN 10
|
||||||
|
WHEN `name` = 'Other' THEN 11
|
||||||
|
ELSE `sort_key`
|
||||||
|
END;
|
||||||
|
-- End: Changes for Guest OS category cleanup
|
||||||
|
|||||||
@ -41,6 +41,7 @@ SELECT
|
|||||||
`vm_template`.`guest_os_id` AS `guest_os_id`,
|
`vm_template`.`guest_os_id` AS `guest_os_id`,
|
||||||
`guest_os`.`uuid` AS `guest_os_uuid`,
|
`guest_os`.`uuid` AS `guest_os_uuid`,
|
||||||
`guest_os`.`display_name` AS `guest_os_name`,
|
`guest_os`.`display_name` AS `guest_os_name`,
|
||||||
|
`guest_os`.`category_id` AS `guest_os_category_id`,
|
||||||
`vm_template`.`bootable` AS `bootable`,
|
`vm_template`.`bootable` AS `bootable`,
|
||||||
`vm_template`.`prepopulate` AS `prepopulate`,
|
`vm_template`.`prepopulate` AS `prepopulate`,
|
||||||
`vm_template`.`cross_zones` AS `cross_zones`,
|
`vm_template`.`cross_zones` AS `cross_zones`,
|
||||||
|
|||||||
@ -21,7 +21,11 @@ import static org.junit.Assert.assertNotNull;
|
|||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -44,8 +48,11 @@ import com.cloud.host.dao.HostDao;
|
|||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
|
import com.cloud.storage.VMTemplateZoneVO;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
|
import com.cloud.utils.db.GenericSearchBuilder;
|
||||||
|
import com.cloud.utils.db.JoinBuilder;
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
|
||||||
@ -55,6 +62,9 @@ public class VMTemplateDaoImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
HostDao hostDao;
|
HostDao hostDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VMTemplateZoneDao templateZoneDao;
|
||||||
|
|
||||||
@Spy
|
@Spy
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
VMTemplateDaoImpl templateDao = new VMTemplateDaoImpl();
|
VMTemplateDaoImpl templateDao = new VMTemplateDaoImpl();
|
||||||
@ -186,4 +196,107 @@ public class VMTemplateDaoImplTest {
|
|||||||
VMTemplateVO result = templateDao.findLatestTemplateByTypeAndHypervisorAndArch(hypervisorType, arch, type);
|
VMTemplateVO result = templateDao.findLatestTemplateByTypeAndHypervisorAndArch(hypervisorType, arch, type);
|
||||||
assertNull(result);
|
assertNull(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mockTemplateZoneJoin() {
|
||||||
|
VMTemplateZoneVO templateZoneVO = mock(VMTemplateZoneVO.class);
|
||||||
|
SearchBuilder<VMTemplateZoneVO> templateZoneVOSearchBuilder = mock(SearchBuilder.class);
|
||||||
|
when(templateZoneVOSearchBuilder.entity()).thenReturn(templateZoneVO);
|
||||||
|
when(templateZoneDao.createSearchBuilder()).thenReturn(templateZoneVOSearchBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListTemplateIsoByArchAndZone_WithDataCenterId() {
|
||||||
|
Long dataCenterId = 1L;
|
||||||
|
CPU.CPUArch arch = CPU.CPUArch.getDefault();
|
||||||
|
Boolean isIso = true;
|
||||||
|
VMTemplateVO templateVO = mock(VMTemplateVO.class);
|
||||||
|
GenericSearchBuilder<VMTemplateVO, Long> searchBuilder = mock(GenericSearchBuilder.class);
|
||||||
|
when(searchBuilder.entity()).thenReturn(templateVO);
|
||||||
|
SearchCriteria<Long>searchCriteria = mock(SearchCriteria.class);
|
||||||
|
when(templateDao.createSearchBuilder(Long.class)).thenReturn(searchBuilder);
|
||||||
|
when(searchBuilder.create()).thenReturn(searchCriteria);
|
||||||
|
mockTemplateZoneJoin();
|
||||||
|
doReturn(new ArrayList<>()).when(templateDao).customSearch(searchCriteria, null);
|
||||||
|
List<Long> result = templateDao.listTemplateIsoByArchVnfAndZone(dataCenterId, arch, isIso, false);
|
||||||
|
assertNotNull(result);
|
||||||
|
verify(searchBuilder, times(1)).select(null, SearchCriteria.Func.DISTINCT, templateVO.getGuestOSId());
|
||||||
|
verify(searchBuilder, times(1)).and(eq("state"), any(), eq(SearchCriteria.Op.IN));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("type"), any(), eq(SearchCriteria.Op.IN));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("arch"), any(), eq(SearchCriteria.Op.EQ));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("isIso"), any(), eq(SearchCriteria.Op.EQ));
|
||||||
|
verify(searchBuilder, times(1)).join(eq("templateZoneSearch"), any(), any(), any(), eq(JoinBuilder.JoinType.INNER));
|
||||||
|
verify(templateDao, times(1)).customSearch(searchCriteria, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListTemplateIsoByArchAndZone_WithoutDataCenterId() {
|
||||||
|
Long dataCenterId = null;
|
||||||
|
CPU.CPUArch arch = CPU.CPUArch.getDefault();
|
||||||
|
Boolean isIso = false;
|
||||||
|
VMTemplateVO templateVO = mock(VMTemplateVO.class);
|
||||||
|
GenericSearchBuilder<VMTemplateVO, Long> searchBuilder = mock(GenericSearchBuilder.class);
|
||||||
|
when(searchBuilder.entity()).thenReturn(templateVO);
|
||||||
|
SearchCriteria<Long>searchCriteria = mock(SearchCriteria.class);
|
||||||
|
when(templateDao.createSearchBuilder(Long.class)).thenReturn(searchBuilder);
|
||||||
|
when(searchBuilder.create()).thenReturn(searchCriteria);
|
||||||
|
doReturn(new ArrayList<>()).when(templateDao).customSearch(searchCriteria, null);
|
||||||
|
List<Long> result = templateDao.listTemplateIsoByArchVnfAndZone(dataCenterId, arch, isIso, false);
|
||||||
|
assertNotNull(result);
|
||||||
|
verify(searchBuilder, times(1)).select(null, SearchCriteria.Func.DISTINCT, templateVO.getGuestOSId());
|
||||||
|
verify(searchBuilder, times(1)).and(eq("state"), any(), eq(SearchCriteria.Op.IN));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("type"), any(), eq(SearchCriteria.Op.IN));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("arch"), any(), eq(SearchCriteria.Op.EQ));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("isIso"), any(), eq(SearchCriteria.Op.NEQ));
|
||||||
|
verify(searchBuilder, never()).join(eq("templateZoneSearch"), any(), any(), any(), eq(JoinBuilder.JoinType.INNER));
|
||||||
|
verify(templateDao, times(1)).customSearch(searchCriteria, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListTemplateIsoByArchAndZone_WithoutArch() {
|
||||||
|
Long dataCenterId = 1L;
|
||||||
|
CPU.CPUArch arch = null;
|
||||||
|
Boolean isIso = true;
|
||||||
|
VMTemplateVO templateVO = mock(VMTemplateVO.class);
|
||||||
|
GenericSearchBuilder<VMTemplateVO, Long> searchBuilder = mock(GenericSearchBuilder.class);
|
||||||
|
when(searchBuilder.entity()).thenReturn(templateVO);
|
||||||
|
SearchCriteria<Long>searchCriteria = mock(SearchCriteria.class);
|
||||||
|
when(templateDao.createSearchBuilder(Long.class)).thenReturn(searchBuilder);
|
||||||
|
when(searchBuilder.create()).thenReturn(searchCriteria);
|
||||||
|
mockTemplateZoneJoin();
|
||||||
|
doReturn(new ArrayList<>()).when(templateDao).customSearch(searchCriteria, null);
|
||||||
|
List<Long> result = templateDao.listTemplateIsoByArchVnfAndZone(dataCenterId, arch, isIso, false);
|
||||||
|
assertNotNull(result);
|
||||||
|
verify(searchBuilder, times(1)).select(null, SearchCriteria.Func.DISTINCT, templateVO.getGuestOSId());
|
||||||
|
verify(searchBuilder, times(1)).and(eq("state"), any(), eq(SearchCriteria.Op.IN));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("type"), any(), eq(SearchCriteria.Op.IN));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("arch"), any(), eq(SearchCriteria.Op.EQ));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("isIso"), any(), eq(SearchCriteria.Op.EQ));
|
||||||
|
verify(searchBuilder, times(1)).join(eq("templateZoneSearch"), any(), any(), any(), eq(JoinBuilder.JoinType.INNER));
|
||||||
|
verify(templateDao, times(1)).customSearch(searchCriteria, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListTemplateIsoByArchAndZone_WithoutIsIso() {
|
||||||
|
Long dataCenterId = 1L;
|
||||||
|
CPU.CPUArch arch = CPU.CPUArch.getDefault();
|
||||||
|
Boolean isIso = null;
|
||||||
|
VMTemplateVO templateVO = mock(VMTemplateVO.class);
|
||||||
|
GenericSearchBuilder<VMTemplateVO, Long> searchBuilder = mock(GenericSearchBuilder.class);
|
||||||
|
when(searchBuilder.entity()).thenReturn(templateVO);
|
||||||
|
SearchCriteria<Long>searchCriteria = mock(SearchCriteria.class);
|
||||||
|
when(templateDao.createSearchBuilder(Long.class)).thenReturn(searchBuilder);
|
||||||
|
when(searchBuilder.create()).thenReturn(searchCriteria);
|
||||||
|
mockTemplateZoneJoin();
|
||||||
|
doReturn(new ArrayList<>()).when(templateDao).customSearch(searchCriteria, null);
|
||||||
|
List<Long> result = templateDao.listTemplateIsoByArchVnfAndZone(dataCenterId, arch, isIso, false);
|
||||||
|
assertNotNull(result);
|
||||||
|
verify(searchBuilder, times(1)).select(null, SearchCriteria.Func.DISTINCT, templateVO.getGuestOSId());
|
||||||
|
verify(searchBuilder, times(1)).and(eq("state"), any(), eq(SearchCriteria.Op.IN));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("type"), any(), eq(SearchCriteria.Op.IN));
|
||||||
|
verify(searchBuilder, times(1)).and(eq("arch"), any(), eq(SearchCriteria.Op.EQ));
|
||||||
|
verify(searchBuilder, never()).and(eq("isIso"), any(), eq(SearchCriteria.Op.NEQ));
|
||||||
|
verify(searchBuilder, never()).and(eq("isIso"), any(), eq(SearchCriteria.Op.EQ));
|
||||||
|
verify(searchBuilder, times(1)).join(eq("templateZoneSearch"), any(), any(), any(), eq(JoinBuilder.JoinType.INNER));
|
||||||
|
verify(templateDao, times(1)).customSearch(searchCriteria, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package com.cloud.dao;
|
package com.cloud.dao;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -56,6 +57,13 @@ public class EntityManagerImpl extends ManagerBase implements EntityManager {
|
|||||||
return dao.findByUuid(uuid);
|
return dao.findByUuid(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> List<T> listByUuids(Class<T> entityType, Collection<String> uuids) {
|
||||||
|
// Finds and returns a unique VO using uuid, null if entity not found in db
|
||||||
|
GenericDao<? extends T, String> dao = (GenericDao<? extends T, String>)GenericDaoBase.getDao(entityType);
|
||||||
|
return (List<T>)dao.listByUuids(uuids);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T findByUuidIncludingRemoved(Class<T> entityType, String uuid) {
|
public <T> T findByUuidIncludingRemoved(Class<T> entityType, String uuid) {
|
||||||
// Finds and returns a unique VO using uuid, null if entity not found in db
|
// Finds and returns a unique VO using uuid, null if entity not found in db
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
package com.cloud.utils.db;
|
package com.cloud.utils.db;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -56,6 +58,10 @@ public interface GenericDao<T, ID extends Serializable> {
|
|||||||
// Finds one unique VO using uuid
|
// Finds one unique VO using uuid
|
||||||
T findByUuid(String uuid);
|
T findByUuid(String uuid);
|
||||||
|
|
||||||
|
default List<T> listByUuids(Collection<String> uuids) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
// Finds one unique VO using uuid including removed entities
|
// Finds one unique VO using uuid including removed entities
|
||||||
T findByUuidIncludingRemoved(String uuid);
|
T findByUuidIncludingRemoved(String uuid);
|
||||||
|
|
||||||
|
|||||||
@ -1006,6 +1006,17 @@ public abstract class GenericDaoBase<T, ID extends Serializable> extends Compone
|
|||||||
return findOneBy(sc);
|
return findOneBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@DB()
|
||||||
|
public List<T> listByUuids(final Collection<String> uuids) {
|
||||||
|
if (org.apache.commons.collections.CollectionUtils.isEmpty(uuids)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
SearchCriteria<T> sc = createSearchCriteria();
|
||||||
|
sc.addAnd("uuid", SearchCriteria.Op.IN, uuids.toArray());
|
||||||
|
return listBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DB()
|
@DB()
|
||||||
public T findByUuidIncludingRemoved(final String uuid) {
|
public T findByUuidIncludingRemoved(final String uuid) {
|
||||||
|
|||||||
@ -39,16 +39,6 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.cloud.bgp.ASNumber;
|
|
||||||
import com.cloud.bgp.ASNumberRange;
|
|
||||||
import com.cloud.dc.ASNumberRangeVO;
|
|
||||||
import com.cloud.dc.ASNumberVO;
|
|
||||||
import com.cloud.dc.VlanDetailsVO;
|
|
||||||
import com.cloud.dc.dao.ASNumberDao;
|
|
||||||
import com.cloud.dc.dao.ASNumberRangeDao;
|
|
||||||
import com.cloud.dc.dao.VlanDetailsDao;
|
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
|
||||||
import com.cloud.storage.BucketVO;
|
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
import org.apache.cloudstack.acl.ControlledEntity;
|
||||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroup;
|
import org.apache.cloudstack.affinity.AffinityGroup;
|
||||||
@ -63,12 +53,12 @@ import org.apache.cloudstack.api.BaseResponseWithAssociatedNetwork;
|
|||||||
import org.apache.cloudstack.api.ResponseGenerator;
|
import org.apache.cloudstack.api.ResponseGenerator;
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
|
import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
|
||||||
|
import org.apache.cloudstack.api.response.ASNRangeResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ASNumberResponse;
|
||||||
import org.apache.cloudstack.api.response.AccountResponse;
|
import org.apache.cloudstack.api.response.AccountResponse;
|
||||||
import org.apache.cloudstack.api.response.ApplicationLoadBalancerInstanceResponse;
|
import org.apache.cloudstack.api.response.ApplicationLoadBalancerInstanceResponse;
|
||||||
import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse;
|
import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse;
|
||||||
import org.apache.cloudstack.api.response.ApplicationLoadBalancerRuleResponse;
|
import org.apache.cloudstack.api.response.ApplicationLoadBalancerRuleResponse;
|
||||||
import org.apache.cloudstack.api.response.ASNRangeResponse;
|
|
||||||
import org.apache.cloudstack.api.response.ASNumberResponse;
|
|
||||||
import org.apache.cloudstack.api.response.AsyncJobResponse;
|
import org.apache.cloudstack.api.response.AsyncJobResponse;
|
||||||
import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
|
import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
|
||||||
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
||||||
@ -99,10 +89,10 @@ import org.apache.cloudstack.api.response.DomainResponse;
|
|||||||
import org.apache.cloudstack.api.response.DomainRouterResponse;
|
import org.apache.cloudstack.api.response.DomainRouterResponse;
|
||||||
import org.apache.cloudstack.api.response.EventResponse;
|
import org.apache.cloudstack.api.response.EventResponse;
|
||||||
import org.apache.cloudstack.api.response.ExtractResponse;
|
import org.apache.cloudstack.api.response.ExtractResponse;
|
||||||
import org.apache.cloudstack.api.response.SharedFSResponse;
|
|
||||||
import org.apache.cloudstack.api.response.FirewallResponse;
|
import org.apache.cloudstack.api.response.FirewallResponse;
|
||||||
import org.apache.cloudstack.api.response.FirewallRuleResponse;
|
import org.apache.cloudstack.api.response.FirewallRuleResponse;
|
||||||
import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse;
|
import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
import org.apache.cloudstack.api.response.GuestOSResponse;
|
import org.apache.cloudstack.api.response.GuestOSResponse;
|
||||||
import org.apache.cloudstack.api.response.GuestOsMappingResponse;
|
import org.apache.cloudstack.api.response.GuestOsMappingResponse;
|
||||||
import org.apache.cloudstack.api.response.GuestVlanRangeResponse;
|
import org.apache.cloudstack.api.response.GuestVlanRangeResponse;
|
||||||
@ -164,6 +154,7 @@ import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
|||||||
import org.apache.cloudstack.api.response.SecurityGroupRuleResponse;
|
import org.apache.cloudstack.api.response.SecurityGroupRuleResponse;
|
||||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.ServiceResponse;
|
import org.apache.cloudstack.api.response.ServiceResponse;
|
||||||
|
import org.apache.cloudstack.api.response.SharedFSResponse;
|
||||||
import org.apache.cloudstack.api.response.Site2SiteCustomerGatewayResponse;
|
import org.apache.cloudstack.api.response.Site2SiteCustomerGatewayResponse;
|
||||||
import org.apache.cloudstack.api.response.Site2SiteVpnConnectionResponse;
|
import org.apache.cloudstack.api.response.Site2SiteVpnConnectionResponse;
|
||||||
import org.apache.cloudstack.api.response.Site2SiteVpnGatewayResponse;
|
import org.apache.cloudstack.api.response.Site2SiteVpnGatewayResponse;
|
||||||
@ -230,10 +221,10 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
|||||||
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.sharedfs.SharedFS;
|
|
||||||
import org.apache.cloudstack.storage.sharedfs.query.vo.SharedFSJoinVO;
|
|
||||||
import org.apache.cloudstack.storage.object.Bucket;
|
import org.apache.cloudstack.storage.object.Bucket;
|
||||||
import org.apache.cloudstack.storage.object.ObjectStore;
|
import org.apache.cloudstack.storage.object.ObjectStore;
|
||||||
|
import org.apache.cloudstack.storage.sharedfs.SharedFS;
|
||||||
|
import org.apache.cloudstack.storage.sharedfs.query.vo.SharedFSJoinVO;
|
||||||
import org.apache.cloudstack.usage.Usage;
|
import org.apache.cloudstack.usage.Usage;
|
||||||
import org.apache.cloudstack.usage.UsageService;
|
import org.apache.cloudstack.usage.UsageService;
|
||||||
import org.apache.cloudstack.usage.UsageTypes;
|
import org.apache.cloudstack.usage.UsageTypes;
|
||||||
@ -241,8 +232,8 @@ import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
|||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import com.cloud.agent.api.VgpuTypesInfo;
|
import com.cloud.agent.api.VgpuTypesInfo;
|
||||||
import com.cloud.api.query.ViewResponseHelper;
|
import com.cloud.api.query.ViewResponseHelper;
|
||||||
@ -271,6 +262,8 @@ import com.cloud.api.query.vo.UserVmJoinVO;
|
|||||||
import com.cloud.api.query.vo.VolumeJoinVO;
|
import com.cloud.api.query.vo.VolumeJoinVO;
|
||||||
import com.cloud.api.query.vo.VpcOfferingJoinVO;
|
import com.cloud.api.query.vo.VpcOfferingJoinVO;
|
||||||
import com.cloud.api.response.ApiResponseSerializer;
|
import com.cloud.api.response.ApiResponseSerializer;
|
||||||
|
import com.cloud.bgp.ASNumber;
|
||||||
|
import com.cloud.bgp.ASNumberRange;
|
||||||
import com.cloud.capacity.Capacity;
|
import com.cloud.capacity.Capacity;
|
||||||
import com.cloud.capacity.CapacityVO;
|
import com.cloud.capacity.CapacityVO;
|
||||||
import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity;
|
import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity;
|
||||||
@ -279,6 +272,8 @@ import com.cloud.configuration.Resource.ResourceOwnerType;
|
|||||||
import com.cloud.configuration.Resource.ResourceType;
|
import com.cloud.configuration.Resource.ResourceType;
|
||||||
import com.cloud.configuration.ResourceCount;
|
import com.cloud.configuration.ResourceCount;
|
||||||
import com.cloud.configuration.ResourceLimit;
|
import com.cloud.configuration.ResourceLimit;
|
||||||
|
import com.cloud.dc.ASNumberRangeVO;
|
||||||
|
import com.cloud.dc.ASNumberVO;
|
||||||
import com.cloud.dc.ClusterDetailsDao;
|
import com.cloud.dc.ClusterDetailsDao;
|
||||||
import com.cloud.dc.ClusterVO;
|
import com.cloud.dc.ClusterVO;
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
@ -289,7 +284,11 @@ import com.cloud.dc.Pod;
|
|||||||
import com.cloud.dc.StorageNetworkIpRange;
|
import com.cloud.dc.StorageNetworkIpRange;
|
||||||
import com.cloud.dc.Vlan;
|
import com.cloud.dc.Vlan;
|
||||||
import com.cloud.dc.Vlan.VlanType;
|
import com.cloud.dc.Vlan.VlanType;
|
||||||
|
import com.cloud.dc.VlanDetailsVO;
|
||||||
import com.cloud.dc.VlanVO;
|
import com.cloud.dc.VlanVO;
|
||||||
|
import com.cloud.dc.dao.ASNumberDao;
|
||||||
|
import com.cloud.dc.dao.ASNumberRangeDao;
|
||||||
|
import com.cloud.dc.dao.VlanDetailsDao;
|
||||||
import com.cloud.domain.Domain;
|
import com.cloud.domain.Domain;
|
||||||
import com.cloud.domain.DomainVO;
|
import com.cloud.domain.DomainVO;
|
||||||
import com.cloud.event.Event;
|
import com.cloud.event.Event;
|
||||||
@ -299,6 +298,7 @@ import com.cloud.gpu.GPU;
|
|||||||
import com.cloud.host.ControlState;
|
import com.cloud.host.ControlState;
|
||||||
import com.cloud.host.Host;
|
import com.cloud.host.Host;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.hypervisor.HypervisorCapabilities;
|
import com.cloud.hypervisor.HypervisorCapabilities;
|
||||||
import com.cloud.network.GuestVlan;
|
import com.cloud.network.GuestVlan;
|
||||||
import com.cloud.network.GuestVlanRange;
|
import com.cloud.network.GuestVlanRange;
|
||||||
@ -377,10 +377,13 @@ import com.cloud.projects.ProjectAccount;
|
|||||||
import com.cloud.projects.ProjectInvitation;
|
import com.cloud.projects.ProjectInvitation;
|
||||||
import com.cloud.region.ha.GlobalLoadBalancerRule;
|
import com.cloud.region.ha.GlobalLoadBalancerRule;
|
||||||
import com.cloud.resource.RollingMaintenanceManager;
|
import com.cloud.resource.RollingMaintenanceManager;
|
||||||
|
import com.cloud.resource.icon.ResourceIconVO;
|
||||||
import com.cloud.server.ResourceIcon;
|
import com.cloud.server.ResourceIcon;
|
||||||
|
import com.cloud.server.ResourceIconManager;
|
||||||
import com.cloud.server.ResourceTag;
|
import com.cloud.server.ResourceTag;
|
||||||
import com.cloud.server.ResourceTag.ResourceObjectType;
|
import com.cloud.server.ResourceTag.ResourceObjectType;
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
|
import com.cloud.storage.BucketVO;
|
||||||
import com.cloud.storage.DataStoreRole;
|
import com.cloud.storage.DataStoreRole;
|
||||||
import com.cloud.storage.DiskOfferingVO;
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
import com.cloud.storage.GuestOS;
|
import com.cloud.storage.GuestOS;
|
||||||
@ -521,6 +524,8 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
BgpPeerDao bgpPeerDao;
|
BgpPeerDao bgpPeerDao;
|
||||||
@Inject
|
@Inject
|
||||||
RoutedIpv4Manager routedIpv4Manager;
|
RoutedIpv4Manager routedIpv4Manager;
|
||||||
|
@Inject
|
||||||
|
ResourceIconManager resourceIconManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserResponse createUserResponse(User user) {
|
public UserResponse createUserResponse(User user) {
|
||||||
@ -3902,6 +3907,30 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GuestOSCategoryResponse createGuestOSCategoryResponse(GuestOsCategory guestOsCategory) {
|
||||||
|
return createGuestOSCategoryResponse(guestOsCategory, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GuestOSCategoryResponse createGuestOSCategoryResponse(GuestOsCategory guestOsCategory, boolean showIcon) {
|
||||||
|
GuestOSCategoryResponse categoryResponse = new GuestOSCategoryResponse();
|
||||||
|
categoryResponse.setId(guestOsCategory.getUuid());
|
||||||
|
categoryResponse.setName(guestOsCategory.getName());
|
||||||
|
categoryResponse.setFeatured(guestOsCategory.isFeatured());
|
||||||
|
categoryResponse.setCreated(guestOsCategory.getCreated());
|
||||||
|
if (showIcon) {
|
||||||
|
ResourceIconVO resourceIcon = ApiDBUtils.getResourceIconByResourceUUID(guestOsCategory.getUuid(),
|
||||||
|
ResourceObjectType.GuestOsCategory);
|
||||||
|
if (resourceIcon != null) {
|
||||||
|
ResourceIconResponse iconResponse = ApiDBUtils.newResourceIconResponse(resourceIcon);
|
||||||
|
categoryResponse.setResourceIconResponse(iconResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
categoryResponse.setObjectName("oscategory");
|
||||||
|
return categoryResponse;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GuestOSResponse createGuestOSResponse(GuestOS guestOS) {
|
public GuestOSResponse createGuestOSResponse(GuestOS guestOS) {
|
||||||
GuestOSResponse response = new GuestOSResponse();
|
GuestOSResponse response = new GuestOSResponse();
|
||||||
@ -5482,4 +5511,39 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
SharedFSJoinVO sharedFSView = ApiDBUtils.newSharedFSView(sharedFS);
|
SharedFSJoinVO sharedFSView = ApiDBUtils.newSharedFSView(sharedFS);
|
||||||
return ApiDBUtils.newSharedFSResponse(view, sharedFSView);
|
return ApiDBUtils.newSharedFSResponse(view, sharedFSView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Map<String, ResourceIcon> getResourceIconsUsingOsCategory(List<TemplateResponse> responses) {
|
||||||
|
Set<Long> guestOsCategoryIds = responses.stream().map(TemplateResponse::getOsTypeCategoryId).collect(Collectors.toSet());
|
||||||
|
Map<Long, ResourceIcon> guestOsCategoryIcons =
|
||||||
|
resourceIconManager.getByResourceTypeAndIds(ResourceTag.ResourceObjectType.GuestOsCategory,
|
||||||
|
guestOsCategoryIds);
|
||||||
|
Map<String, ResourceIcon> vmIcons = new HashMap<>();
|
||||||
|
for (TemplateResponse response : responses) {
|
||||||
|
vmIcons.put(response.getId(), guestOsCategoryIcons.get(response.getOsTypeCategoryId()));
|
||||||
|
}
|
||||||
|
return vmIcons;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTemplateIsoResponsesForIcons(List<TemplateResponse> responses,
|
||||||
|
ResourceTag.ResourceObjectType type) {
|
||||||
|
if (CollectionUtils.isEmpty(responses)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<String> uuids = responses.stream().map(TemplateResponse::getId).collect(Collectors.toSet());
|
||||||
|
Map<String, ResourceIcon> templateIcons = resourceIconManager.getByResourceTypeAndUuids(type, uuids);
|
||||||
|
List<TemplateResponse> noTemplateIconResponses = responses
|
||||||
|
.stream()
|
||||||
|
.filter(r -> !templateIcons.containsKey(r.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
templateIcons.putAll(getResourceIconsUsingOsCategory(noTemplateIconResponses));
|
||||||
|
for (TemplateResponse response : responses) {
|
||||||
|
ResourceIcon icon = templateIcons.get(response.getId());
|
||||||
|
if (icon == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ResourceIconResponse iconResponse = createResourceIconResponse(icon);
|
||||||
|
response.setResourceIconResponse(iconResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -316,6 +316,7 @@ import com.cloud.storage.VolumeApiServiceImpl;
|
|||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.dao.BucketDao;
|
import com.cloud.storage.dao.BucketDao;
|
||||||
import com.cloud.storage.dao.DiskOfferingDao;
|
import com.cloud.storage.dao.DiskOfferingDao;
|
||||||
|
import com.cloud.storage.dao.GuestOSDao;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.storage.dao.StoragePoolTagsDao;
|
import com.cloud.storage.dao.StoragePoolTagsDao;
|
||||||
import com.cloud.storage.dao.VMTemplateDao;
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
@ -643,6 +644,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
@Inject
|
@Inject
|
||||||
HostPodDao podDao;
|
HostPodDao podDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
GuestOSDao guestOSDao;
|
||||||
|
|
||||||
private SearchCriteria<ServiceOfferingJoinVO> getMinimumCpuServiceOfferingJoinSearchCriteria(int cpu) {
|
private SearchCriteria<ServiceOfferingJoinVO> getMinimumCpuServiceOfferingJoinSearchCriteria(int cpu) {
|
||||||
SearchCriteria<ServiceOfferingJoinVO> sc = _srvOfferingJoinDao.createSearchCriteria();
|
SearchCriteria<ServiceOfferingJoinVO> sc = _srvOfferingJoinDao.createSearchCriteria();
|
||||||
SearchCriteria<ServiceOfferingJoinVO> sc1 = _srvOfferingJoinDao.createSearchCriteria();
|
SearchCriteria<ServiceOfferingJoinVO> sc1 = _srvOfferingJoinDao.createSearchCriteria();
|
||||||
@ -4791,7 +4795,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), cmd.getStoragePoolId(),
|
null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), cmd.getStoragePoolId(),
|
||||||
cmd.getImageStoreId(), hypervisorType, showDomr, cmd.listInReadyState(), permittedAccounts, caller,
|
cmd.getImageStoreId(), hypervisorType, showDomr, cmd.listInReadyState(), permittedAccounts, caller,
|
||||||
listProjectResourcesCriteria, tags, showRemovedTmpl, cmd.getIds(), parentTemplateId, cmd.getShowUnique(),
|
listProjectResourcesCriteria, tags, showRemovedTmpl, cmd.getIds(), parentTemplateId, cmd.getShowUnique(),
|
||||||
templateType, isVnf, cmd.getArch());
|
templateType, isVnf, cmd.getArch(), cmd.getOsCategoryId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<List<TemplateJoinVO>, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword,
|
private Pair<List<TemplateJoinVO>, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword,
|
||||||
@ -4800,7 +4804,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
boolean showDomr, boolean onlyReady, List<Account> permittedAccounts, Account caller,
|
boolean showDomr, boolean onlyReady, List<Account> permittedAccounts, Account caller,
|
||||||
ListProjectResourcesCriteria listProjectResourcesCriteria, Map<String, String> tags,
|
ListProjectResourcesCriteria listProjectResourcesCriteria, Map<String, String> tags,
|
||||||
boolean showRemovedTmpl, List<Long> ids, Long parentTemplateId, Boolean showUnique, String templateType,
|
boolean showRemovedTmpl, List<Long> ids, Long parentTemplateId, Boolean showUnique, String templateType,
|
||||||
Boolean isVnf, CPU.CPUArch arch) {
|
Boolean isVnf, CPU.CPUArch arch, Long osCategoryId) {
|
||||||
|
|
||||||
// check if zone is configured, if not, just return empty list
|
// check if zone is configured, if not, just return empty list
|
||||||
List<HypervisorType> hypers = null;
|
List<HypervisorType> hypers = null;
|
||||||
@ -4828,10 +4832,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
|
|
||||||
if (storagePoolId != null) {
|
if (storagePoolId != null) {
|
||||||
SearchBuilder<VMTemplateStoragePoolVO> storagePoolSb = templatePoolDao.createSearchBuilder();
|
SearchBuilder<VMTemplateStoragePoolVO> storagePoolSb = templatePoolDao.createSearchBuilder();
|
||||||
storagePoolSb.and("pool_id", storagePoolSb.entity().getPoolId(), SearchCriteria.Op.EQ);
|
|
||||||
sb.join("storagePool", storagePoolSb, storagePoolSb.entity().getTemplateId(), sb.entity().getId(), JoinBuilder.JoinType.INNER);
|
sb.join("storagePool", storagePoolSb, storagePoolSb.entity().getTemplateId(), sb.entity().getId(), JoinBuilder.JoinType.INNER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (osCategoryId != null) {
|
||||||
|
sb.and("guestOsIdIN", sb.entity().getGuestOSId(), Op.IN);
|
||||||
|
}
|
||||||
|
|
||||||
SearchCriteria<TemplateJoinVO> sc = sb.create();
|
SearchCriteria<TemplateJoinVO> sc = sb.create();
|
||||||
|
|
||||||
if (imageStoreId != null) {
|
if (imageStoreId != null) {
|
||||||
@ -4846,6 +4853,15 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
sc.setJoinParameters("storagePool", "pool_id", storagePoolId);
|
sc.setJoinParameters("storagePool", "pool_id", storagePoolId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (osCategoryId != null) {
|
||||||
|
List<Long> guestOsIds = guestOSDao.listIdsByCategoryId(osCategoryId);
|
||||||
|
if (CollectionUtils.isNotEmpty(guestOsIds)) {
|
||||||
|
sc.setParameters("guestOsIdIN", guestOsIds.toArray());
|
||||||
|
} else {
|
||||||
|
return new Pair<>(new ArrayList<>(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// verify templateId parameter and specially handle it
|
// verify templateId parameter and specially handle it
|
||||||
if (templateId != null) {
|
if (templateId != null) {
|
||||||
template = _templateDao.findByIdIncludingRemoved(templateId); // Done for backward compatibility - Bug-5221
|
template = _templateDao.findByIdIncludingRemoved(templateId); // Done for backward compatibility - Bug-5221
|
||||||
@ -5231,7 +5247,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(),
|
return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(),
|
||||||
cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), cmd.getStoragePoolId(), cmd.getImageStoreId(),
|
cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), cmd.getStoragePoolId(), cmd.getImageStoreId(),
|
||||||
hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria,
|
hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria,
|
||||||
tags, showRemovedISO, null, null, cmd.getShowUnique(), null, null, cmd.getArch());
|
tags, showRemovedISO, null, null, cmd.getShowUnique(), null, null,
|
||||||
|
cmd.getArch(), cmd.getOsCategoryId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -28,54 +28,53 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.cloud.deployasis.DeployAsIsConstants;
|
|
||||||
import com.cloud.deployasis.TemplateDeployAsIsDetailVO;
|
|
||||||
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
|
|
||||||
import com.cloud.storage.DataStoreRole;
|
|
||||||
import com.cloud.storage.VMTemplateStoragePoolVO;
|
|
||||||
import com.cloud.storage.dao.VMTemplatePoolDao;
|
|
||||||
import com.cloud.storage.VnfTemplateDetailVO;
|
|
||||||
import com.cloud.storage.VnfTemplateNicVO;
|
|
||||||
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
|
||||||
import com.cloud.storage.dao.VnfTemplateNicDao;
|
|
||||||
import com.cloud.user.dao.UserDataDao;
|
|
||||||
import org.apache.cloudstack.annotation.AnnotationService;
|
import org.apache.cloudstack.annotation.AnnotationService;
|
||||||
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.response.VnfNicResponse;
|
|
||||||
import org.apache.cloudstack.api.response.VnfTemplateResponse;
|
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
|
||||||
import org.apache.cloudstack.utils.security.DigestHelper;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
import org.apache.cloudstack.api.response.ChildTemplateResponse;
|
import org.apache.cloudstack.api.response.ChildTemplateResponse;
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
import org.apache.cloudstack.api.response.VnfNicResponse;
|
||||||
|
import org.apache.cloudstack.api.response.VnfTemplateResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState;
|
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.query.QueryService;
|
import org.apache.cloudstack.query.QueryService;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||||
|
import org.apache.cloudstack.utils.security.DigestHelper;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.cloud.api.ApiDBUtils;
|
import com.cloud.api.ApiDBUtils;
|
||||||
import com.cloud.api.ApiResponseHelper;
|
import com.cloud.api.ApiResponseHelper;
|
||||||
import com.cloud.api.query.vo.ResourceTagJoinVO;
|
import com.cloud.api.query.vo.ResourceTagJoinVO;
|
||||||
import com.cloud.api.query.vo.TemplateJoinVO;
|
import com.cloud.api.query.vo.TemplateJoinVO;
|
||||||
|
import com.cloud.deployasis.DeployAsIsConstants;
|
||||||
|
import com.cloud.deployasis.TemplateDeployAsIsDetailVO;
|
||||||
|
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
|
import com.cloud.storage.DataStoreRole;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.Storage.TemplateType;
|
import com.cloud.storage.Storage.TemplateType;
|
||||||
|
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||||
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
import com.cloud.storage.dao.VMTemplateDao;
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
||||||
|
import com.cloud.storage.dao.VMTemplatePoolDao;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateNicDao;
|
||||||
import com.cloud.template.VirtualMachineTemplate;
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountService;
|
import com.cloud.user.AccountService;
|
||||||
|
import com.cloud.user.dao.UserDataDao;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
@ -262,6 +261,7 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
|
|
||||||
templateResponse.setOsTypeId(template.getGuestOSUuid());
|
templateResponse.setOsTypeId(template.getGuestOSUuid());
|
||||||
templateResponse.setOsTypeName(template.getGuestOSName());
|
templateResponse.setOsTypeName(template.getGuestOSName());
|
||||||
|
templateResponse.setOsTypeCategoryId(template.getGuestOSCategoryId());
|
||||||
|
|
||||||
// populate owner.
|
// populate owner.
|
||||||
ApiResponseHelper.populateOwner(templateResponse, template);
|
ApiResponseHelper.populateOwner(templateResponse, template);
|
||||||
@ -402,6 +402,7 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
response.setFormat(result.getFormat());
|
response.setFormat(result.getFormat());
|
||||||
response.setOsTypeId(result.getGuestOSUuid());
|
response.setOsTypeId(result.getGuestOSUuid());
|
||||||
response.setOsTypeName(result.getGuestOSName());
|
response.setOsTypeName(result.getGuestOSName());
|
||||||
|
response.setOsTypeCategoryId(result.getGuestOSCategoryId());
|
||||||
response.setBootable(result.isBootable());
|
response.setBootable(result.isBootable());
|
||||||
response.setHypervisor(result.getHypervisorType().getHypervisorDisplayName());
|
response.setHypervisor(result.getHypervisorType().getHypervisorDisplayName());
|
||||||
response.setDynamicallyScalable(result.isDynamicallyScalable());
|
response.setDynamicallyScalable(result.isDynamicallyScalable());
|
||||||
@ -490,6 +491,7 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
|
|
||||||
isoResponse.setOsTypeId(iso.getGuestOSUuid());
|
isoResponse.setOsTypeId(iso.getGuestOSUuid());
|
||||||
isoResponse.setOsTypeName(iso.getGuestOSName());
|
isoResponse.setOsTypeName(iso.getGuestOSName());
|
||||||
|
isoResponse.setOsTypeCategoryId(iso.getGuestOSCategoryId());
|
||||||
isoResponse.setBits(iso.getBits());
|
isoResponse.setBits(iso.getBits());
|
||||||
isoResponse.setPasswordEnabled(iso.isEnablePassword());
|
isoResponse.setPasswordEnabled(iso.isEnablePassword());
|
||||||
|
|
||||||
|
|||||||
@ -27,19 +27,19 @@ import javax.persistence.Table;
|
|||||||
import javax.persistence.Temporal;
|
import javax.persistence.Temporal;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
import com.cloud.cpu.CPU;
|
|
||||||
import com.cloud.user.Account;
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||||
|
import org.apache.cloudstack.util.CPUArchConverter;
|
||||||
|
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
||||||
|
|
||||||
|
import com.cloud.cpu.CPU;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.storage.ScopeType;
|
import com.cloud.storage.ScopeType;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
||||||
import com.cloud.template.VirtualMachineTemplate;
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
import com.cloud.template.VirtualMachineTemplate.State;
|
import com.cloud.template.VirtualMachineTemplate.State;
|
||||||
|
import com.cloud.user.Account;
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
import org.apache.cloudstack.util.CPUArchConverter;
|
|
||||||
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "template_view")
|
@Table(name = "template_view")
|
||||||
@ -112,6 +112,9 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont
|
|||||||
@Column(name = "guest_os_name")
|
@Column(name = "guest_os_name")
|
||||||
private String guestOSName;
|
private String guestOSName;
|
||||||
|
|
||||||
|
@Column(name = "guest_os_category_id")
|
||||||
|
private Long guestOSCategoryId;
|
||||||
|
|
||||||
@Column(name = "bootable")
|
@Column(name = "bootable")
|
||||||
private boolean bootable = true;
|
private boolean bootable = true;
|
||||||
|
|
||||||
@ -405,6 +408,10 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont
|
|||||||
return guestOSName;
|
return guestOSName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getGuestOSCategoryId() {
|
||||||
|
return guestOSCategoryId;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isBootable() {
|
public boolean isBootable() {
|
||||||
return bootable;
|
return bootable;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,11 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.resourceicon;
|
package com.cloud.resourceicon;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -247,4 +250,18 @@ public class ResourceIconManagerImpl extends ManagerBase implements ResourceIcon
|
|||||||
sc.setParameters("resourceType", resourceType);
|
sc.setParameters("resourceType", resourceType);
|
||||||
return resourceIconDao.search(sc, null);
|
return resourceIconDao.search(sc, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Long, ResourceIcon> getByResourceTypeAndIds(ResourceTag.ResourceObjectType resourceType, Collection<Long> resourceIds) {
|
||||||
|
List<ResourceIconVO> icons = resourceIconDao.listByResourceTypeAndIds(resourceType, resourceIds);
|
||||||
|
return icons.stream().collect(Collectors.toMap(ResourceIconVO::getResourceId, Function.identity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ResourceIcon> getByResourceTypeAndUuids(ResourceTag.ResourceObjectType resourceType, Collection<String> resourceUuids) {
|
||||||
|
List<ResourceIconVO> icons = resourceIconDao.listByResourceTypeAndUuids(resourceType, resourceUuids);
|
||||||
|
return icons.stream().collect(Collectors.toMap(ResourceIconVO::getResourceUuid, Function.identity()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,12 +89,15 @@ import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd;
|
|||||||
import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmdByAdmin;
|
import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmdByAdmin;
|
||||||
import org.apache.cloudstack.api.command.admin.domain.MoveDomainCmd;
|
import org.apache.cloudstack.api.command.admin.domain.MoveDomainCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd;
|
import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCategoryCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCmd;
|
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsMappingCmd;
|
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsMappingCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.DeleteGuestOsCategoryCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.GetHypervisorGuestOsNamesCmd;
|
import org.apache.cloudstack.api.command.admin.guest.GetHypervisorGuestOsNamesCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.ListGuestOsMappingCmd;
|
import org.apache.cloudstack.api.command.admin.guest.ListGuestOsMappingCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsCmd;
|
import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsMappingCmd;
|
import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsMappingCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsCategoryCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsCmd;
|
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsMappingCmd;
|
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsMappingCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.host.AddHostCmd;
|
import org.apache.cloudstack.api.command.admin.host.AddHostCmd;
|
||||||
@ -643,6 +646,8 @@ import org.apache.cloudstack.utils.identity.ManagementServerNode;
|
|||||||
import org.apache.cloudstack.vm.lease.VMLeaseManager;
|
import org.apache.cloudstack.vm.lease.VMLeaseManager;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.cloud.agent.AgentManager;
|
import com.cloud.agent.AgentManager;
|
||||||
@ -2752,29 +2757,114 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<List<? extends GuestOsCategory>, Integer> listGuestOSCategoriesByCriteria(final ListGuestOsCategoriesCmd cmd) {
|
public Pair<List<? extends GuestOsCategory>, Integer> listGuestOSCategoriesByCriteria(final ListGuestOsCategoriesCmd cmd) {
|
||||||
final Filter searchFilter = new Filter(GuestOSCategoryVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
|
final Filter searchFilter = new Filter(GuestOSCategoryVO.class, "sortKey", true,
|
||||||
|
cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||||
|
searchFilter.addOrderBy(GuestOSCategoryVO.class, "id", true);
|
||||||
final Long id = cmd.getId();
|
final Long id = cmd.getId();
|
||||||
final String name = cmd.getName();
|
final String name = cmd.getName();
|
||||||
final String keyword = cmd.getKeyword();
|
final String keyword = cmd.getKeyword();
|
||||||
|
final Boolean featured = cmd.isFeatured();
|
||||||
|
final Boolean isIso = cmd.isIso();
|
||||||
|
final Boolean isVnf = cmd.isVnf();
|
||||||
|
final Long zoneId = cmd.getZoneId();
|
||||||
|
final CPU.CPUArch arch = cmd.getArch();
|
||||||
|
|
||||||
final SearchCriteria<GuestOSCategoryVO> sc = _guestOSCategoryDao.createSearchCriteria();
|
final SearchBuilder<GuestOSCategoryVO> sb = _guestOSCategoryDao.createSearchBuilder();
|
||||||
|
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
|
||||||
|
sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
|
||||||
|
sb.and("keyword", sb.entity().getName(), SearchCriteria.Op.LIKE);
|
||||||
|
sb.and("featured", sb.entity().isFeatured(), SearchCriteria.Op.EQ);
|
||||||
|
if (ObjectUtils.anyNotNull(zoneId, arch, isIso, isVnf)) {
|
||||||
|
final SearchBuilder<GuestOSVO> guestOsSearch = _guestOSDao.createSearchBuilder();
|
||||||
|
guestOsSearch.and("ids", guestOsSearch.entity().getId(), SearchCriteria.Op.IN);
|
||||||
|
sb.join("guestOsSearch", guestOsSearch, guestOsSearch.entity().getCategoryId(), sb.entity().getId(),
|
||||||
|
JoinType.INNER);
|
||||||
|
guestOsSearch.done();
|
||||||
|
sb.groupBy(sb.entity().getId());
|
||||||
|
}
|
||||||
|
sb.done();
|
||||||
|
SearchCriteria<GuestOSCategoryVO> sc = sb.create();
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
sc.addAnd("id", SearchCriteria.Op.EQ, id);
|
sc.setParameters("id", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + name + "%");
|
sc.setParameters("name", "%" + name + "%");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyword != null) {
|
if (keyword != null) {
|
||||||
sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
|
sc.setParameters("name", "%" + keyword + "%");
|
||||||
|
}
|
||||||
|
if (featured != null) {
|
||||||
|
sc.setParameters("featured", featured);
|
||||||
|
}
|
||||||
|
if (ObjectUtils.anyNotNull(zoneId, arch, isIso, isVnf)) {
|
||||||
|
List<Long> guestOsIds = templateDao.listTemplateIsoByArchVnfAndZone(zoneId, arch, isIso, isVnf);
|
||||||
|
if (CollectionUtils.isEmpty(guestOsIds)) {
|
||||||
|
return new Pair<>(Collections.emptyList(), 0);
|
||||||
|
}
|
||||||
|
sc.setJoinParameters("guestOsSearch", "ids", guestOsIds.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
final Pair<List<GuestOSCategoryVO>, Integer> result = _guestOSCategoryDao.searchAndCount(sc, searchFilter);
|
final Pair<List<GuestOSCategoryVO>, Integer> result = _guestOSCategoryDao.searchAndCount(sc, searchFilter);
|
||||||
return new Pair<>(result.first(), result.second());
|
return new Pair<>(result.first(), result.second());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@ActionEvent(eventType = EventTypes.EVENT_GUEST_OS_CATEGORY_ADD, eventDescription = "adding OS category")
|
||||||
|
public GuestOsCategory addGuestOsCategory(AddGuestOsCategoryCmd cmd) {
|
||||||
|
final String name = cmd.getName();
|
||||||
|
final boolean featured = cmd.isFeatured();
|
||||||
|
final GuestOSCategoryVO guestOSCategory = new GuestOSCategoryVO(name, featured);
|
||||||
|
GuestOsCategory guestOsCategory = _guestOSCategoryDao.persist(guestOSCategory);
|
||||||
|
CallContext.current().setEventResourceId(guestOsCategory.getId());
|
||||||
|
CallContext.current().setEventResourceType(ApiCommandResourceType.GuestOsCategory);
|
||||||
|
return guestOSCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@ActionEvent(eventType = EventTypes.EVENT_GUEST_OS_CATEGORY_UPDATE, eventDescription = "updating OS category")
|
||||||
|
public GuestOsCategory updateGuestOsCategory(UpdateGuestOsCategoryCmd cmd) {
|
||||||
|
final long id = cmd.getId();
|
||||||
|
final String name = cmd.getName();
|
||||||
|
final Boolean featured = cmd.isFeatured();
|
||||||
|
Integer sortKey = cmd.getSortKey();
|
||||||
|
final GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(id);
|
||||||
|
if (guestOSCategory == null) {
|
||||||
|
throw new InvalidParameterValueException("Invalid OS category ID specified");
|
||||||
|
}
|
||||||
|
if (ObjectUtils.allNull(name, featured, sortKey)) {
|
||||||
|
return guestOSCategory;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(name)) {
|
||||||
|
guestOSCategory.setName(name);
|
||||||
|
}
|
||||||
|
if (featured != null) {
|
||||||
|
guestOSCategory.setFeatured(featured);
|
||||||
|
}
|
||||||
|
if (sortKey != null) {
|
||||||
|
guestOSCategory.setSortKey(sortKey);
|
||||||
|
}
|
||||||
|
if (!_guestOSCategoryDao.update(id, guestOSCategory)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return guestOSCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@ActionEvent(eventType = EventTypes.EVENT_GUEST_OS_CATEGORY_DELETE, eventDescription = "deleting OS category")
|
||||||
|
public boolean deleteGuestOsCategory(DeleteGuestOsCategoryCmd cmd) {
|
||||||
|
final long id = cmd.getId();
|
||||||
|
final GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(id);
|
||||||
|
if (guestOSCategory == null) {
|
||||||
|
throw new InvalidParameterValueException("Invalid OS category ID specified");
|
||||||
|
}
|
||||||
|
List<Long> guestOses = _guestOSDao.listIdsByCategoryId(id);
|
||||||
|
if (!guestOses.isEmpty()) {
|
||||||
|
throw new InvalidParameterValueException(String.format(
|
||||||
|
"Unable to delete the OS category. %d guest OS exist for it.", guestOses.size()));
|
||||||
|
}
|
||||||
|
return _guestOSCategoryDao.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<List<? extends GuestOSHypervisor>, Integer> listGuestOSMappingByCriteria(final ListGuestOsMappingCmd cmd) {
|
public Pair<List<? extends GuestOSHypervisor>, Integer> listGuestOSMappingByCriteria(final ListGuestOsMappingCmd cmd) {
|
||||||
final String guestOsId = "guestOsId";
|
final String guestOsId = "guestOsId";
|
||||||
@ -2992,6 +3082,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
public GuestOS updateGuestOs(final UpdateGuestOsCmd cmd) {
|
public GuestOS updateGuestOs(final UpdateGuestOsCmd cmd) {
|
||||||
final Long id = cmd.getId();
|
final Long id = cmd.getId();
|
||||||
final String displayName = cmd.getOsDisplayName();
|
final String displayName = cmd.getOsDisplayName();
|
||||||
|
final Long osCategoryId = cmd.getOsCategoryId();
|
||||||
|
final Boolean display = cmd.getForDisplay();
|
||||||
|
final Map<String, String> details = cmd.getDetails();
|
||||||
|
boolean updateNeeded = false;
|
||||||
|
|
||||||
//check if guest OS exists
|
//check if guest OS exists
|
||||||
final GuestOS guestOsHandle = ApiDBUtils.findGuestOSById(id);
|
final GuestOS guestOsHandle = ApiDBUtils.findGuestOSById(id);
|
||||||
@ -2999,27 +3093,46 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
throw new InvalidParameterValueException("Guest OS not found. Please specify a valid ID for the Guest OS");
|
throw new InvalidParameterValueException("Guest OS not found. Please specify a valid ID for the Guest OS");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!guestOsHandle.getIsUserDefined()) {
|
//Check if update is needed
|
||||||
|
if (StringUtils.isNotBlank(displayName) && !displayName.equals(guestOsHandle.getDisplayName())) {
|
||||||
|
//Check if another Guest OS by same name exists
|
||||||
|
final GuestOS duplicate = ApiDBUtils.findGuestOSByDisplayName(displayName);
|
||||||
|
if (duplicate != null) {
|
||||||
|
throw new InvalidParameterValueException("The specified Guest OS name : " + displayName + " already exists. Please specify a unique guest OS name");
|
||||||
|
}
|
||||||
|
updateNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (osCategoryId != null) {
|
||||||
|
if (_guestOSCategoryDao.findById(osCategoryId) == null) {
|
||||||
|
throw new InvalidParameterValueException("Invalid OS category ID specified");
|
||||||
|
}
|
||||||
|
updateNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!guestOsHandle.getIsUserDefined() && (StringUtils.isNotBlank(displayName) || MapUtils.isNotEmpty(details)
|
||||||
|
|| display != null)) {
|
||||||
throw new InvalidParameterValueException("Unable to modify system defined guest OS");
|
throw new InvalidParameterValueException("Unable to modify system defined guest OS");
|
||||||
}
|
}
|
||||||
|
|
||||||
persistGuestOsDetails(cmd.getDetails(), id);
|
if (MapUtils.isNotEmpty(details)) {
|
||||||
|
persistGuestOsDetails(details, id);
|
||||||
|
}
|
||||||
|
|
||||||
//Check if update is needed
|
if (!updateNeeded) {
|
||||||
if (displayName.equals(guestOsHandle.getDisplayName())) {
|
|
||||||
return guestOsHandle;
|
return guestOsHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if another Guest OS by same name exists
|
|
||||||
final GuestOS duplicate = ApiDBUtils.findGuestOSByDisplayName(displayName);
|
|
||||||
if (duplicate != null) {
|
|
||||||
throw new InvalidParameterValueException("The specified Guest OS name : " + displayName + " already exists. Please specify a unique guest OS name");
|
|
||||||
}
|
|
||||||
final GuestOSVO guestOs = _guestOSDao.createForUpdate(id);
|
final GuestOSVO guestOs = _guestOSDao.createForUpdate(id);
|
||||||
guestOs.setDisplayName(displayName);
|
if (StringUtils.isNotBlank(displayName)) {
|
||||||
|
guestOs.setDisplayName(displayName);
|
||||||
|
}
|
||||||
if (cmd.getForDisplay() != null) {
|
if (cmd.getForDisplay() != null) {
|
||||||
guestOs.setDisplay(cmd.getForDisplay());
|
guestOs.setDisplay(cmd.getForDisplay());
|
||||||
}
|
}
|
||||||
|
if (osCategoryId != null) {
|
||||||
|
guestOs.setCategoryId(osCategoryId);
|
||||||
|
}
|
||||||
if (_guestOSDao.update(id, guestOs)) {
|
if (_guestOSDao.update(id, guestOs)) {
|
||||||
return _guestOSDao.findById(id);
|
return _guestOSDao.findById(id);
|
||||||
} else {
|
} else {
|
||||||
@ -3722,6 +3835,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
cmdList.add(ListPortForwardingRulesCmd.class);
|
cmdList.add(ListPortForwardingRulesCmd.class);
|
||||||
cmdList.add(UpdatePortForwardingRuleCmd.class);
|
cmdList.add(UpdatePortForwardingRuleCmd.class);
|
||||||
cmdList.add(ListGuestOsCategoriesCmd.class);
|
cmdList.add(ListGuestOsCategoriesCmd.class);
|
||||||
|
cmdList.add(AddGuestOsCategoryCmd.class);
|
||||||
|
cmdList.add(UpdateGuestOsCategoryCmd.class);
|
||||||
|
cmdList.add(DeleteGuestOsCategoryCmd.class);
|
||||||
cmdList.add(ListGuestOsCmd.class);
|
cmdList.add(ListGuestOsCmd.class);
|
||||||
cmdList.add(ListGuestOsMappingCmd.class);
|
cmdList.add(ListGuestOsMappingCmd.class);
|
||||||
cmdList.add(AddGuestOsCmd.class);
|
cmdList.add(AddGuestOsCmd.class);
|
||||||
|
|||||||
@ -58,6 +58,7 @@ import com.cloud.server.ResourceManagerUtil;
|
|||||||
import com.cloud.server.ResourceTag;
|
import com.cloud.server.ResourceTag;
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
import com.cloud.storage.DiskOfferingVO;
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
|
import com.cloud.storage.GuestOsCategory;
|
||||||
import com.cloud.storage.SnapshotPolicyVO;
|
import com.cloud.storage.SnapshotPolicyVO;
|
||||||
import com.cloud.storage.SnapshotVO;
|
import com.cloud.storage.SnapshotVO;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
@ -117,6 +118,7 @@ public class ResourceManagerUtilImpl implements ResourceManagerUtil {
|
|||||||
s_typeMap.put(ResourceTag.ResourceObjectType.NetworkOffering, NetworkOfferingVO.class);
|
s_typeMap.put(ResourceTag.ResourceObjectType.NetworkOffering, NetworkOfferingVO.class);
|
||||||
s_typeMap.put(ResourceTag.ResourceObjectType.VpcOffering, VpcOfferingVO.class);
|
s_typeMap.put(ResourceTag.ResourceObjectType.VpcOffering, VpcOfferingVO.class);
|
||||||
s_typeMap.put(ResourceTag.ResourceObjectType.Domain, DomainVO.class);
|
s_typeMap.put(ResourceTag.ResourceObjectType.Domain, DomainVO.class);
|
||||||
|
s_typeMap.put(ResourceTag.ResourceObjectType.GuestOsCategory, GuestOsCategory.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|||||||
@ -16,37 +16,36 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.api;
|
package com.cloud.api;
|
||||||
|
|
||||||
import com.cloud.capacity.Capacity;
|
import static org.junit.Assert.assertEquals;
|
||||||
import com.cloud.configuration.Resource;
|
import static org.junit.Assert.assertNull;
|
||||||
import com.cloud.domain.DomainVO;
|
import static org.junit.Assert.assertTrue;
|
||||||
import com.cloud.network.PublicIpQuarantine;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import com.cloud.network.as.AutoScaleVmGroup;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import com.cloud.network.as.AutoScaleVmGroupVO;
|
import static org.mockito.Mockito.verify;
|
||||||
import com.cloud.network.as.AutoScaleVmProfileVO;
|
import static org.mockito.Mockito.when;
|
||||||
import com.cloud.network.as.dao.AutoScaleVmGroupVmMapDao;
|
|
||||||
import com.cloud.network.dao.IPAddressDao;
|
import java.lang.reflect.Field;
|
||||||
import com.cloud.network.dao.IPAddressVO;
|
import java.text.ParseException;
|
||||||
import com.cloud.network.dao.LoadBalancerVO;
|
import java.text.SimpleDateFormat;
|
||||||
import com.cloud.network.dao.NetworkServiceMapDao;
|
import java.util.Arrays;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import java.util.Collections;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import java.util.Date;
|
||||||
import com.cloud.usage.UsageVO;
|
import java.util.HashMap;
|
||||||
import com.cloud.user.Account;
|
import java.util.List;
|
||||||
import com.cloud.user.AccountManager;
|
import java.util.Map;
|
||||||
import com.cloud.user.AccountVO;
|
import java.util.Set;
|
||||||
import com.cloud.user.User;
|
import java.util.TimeZone;
|
||||||
import com.cloud.user.UserData;
|
import java.util.UUID;
|
||||||
import com.cloud.user.UserDataVO;
|
|
||||||
import com.cloud.user.UserVO;
|
|
||||||
import com.cloud.user.dao.UserDataDao;
|
|
||||||
import com.cloud.utils.net.Ip;
|
|
||||||
import com.cloud.vm.NicSecondaryIp;
|
|
||||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||||
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
||||||
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
|
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
|
||||||
import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse;
|
import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse;
|
||||||
|
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||||
import org.apache.cloudstack.api.response.IpQuarantineResponse;
|
import org.apache.cloudstack.api.response.IpQuarantineResponse;
|
||||||
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
|
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
||||||
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
|
import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
|
||||||
import org.apache.cloudstack.api.response.UsageRecordResponse;
|
import org.apache.cloudstack.api.response.UsageRecordResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
@ -63,21 +62,38 @@ import org.mockito.MockedStatic;
|
|||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import com.cloud.capacity.Capacity;
|
||||||
import java.text.ParseException;
|
import com.cloud.configuration.Resource;
|
||||||
import java.text.SimpleDateFormat;
|
import com.cloud.domain.DomainVO;
|
||||||
import java.util.Date;
|
import com.cloud.network.PublicIpQuarantine;
|
||||||
import java.util.List;
|
import com.cloud.network.as.AutoScaleVmGroup;
|
||||||
import java.util.TimeZone;
|
import com.cloud.network.as.AutoScaleVmGroupVO;
|
||||||
import java.util.UUID;
|
import com.cloud.network.as.AutoScaleVmProfileVO;
|
||||||
|
import com.cloud.network.as.dao.AutoScaleVmGroupVmMapDao;
|
||||||
import static org.junit.Assert.assertEquals;
|
import com.cloud.network.dao.IPAddressDao;
|
||||||
import static org.junit.Assert.assertNull;
|
import com.cloud.network.dao.IPAddressVO;
|
||||||
import static org.junit.Assert.assertTrue;
|
import com.cloud.network.dao.LoadBalancerVO;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import com.cloud.network.dao.NetworkServiceMapDao;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
import static org.mockito.Mockito.when;
|
import com.cloud.resource.icon.ResourceIconVO;
|
||||||
|
import com.cloud.server.ResourceIcon;
|
||||||
|
import com.cloud.server.ResourceIconManager;
|
||||||
|
import com.cloud.server.ResourceTag;
|
||||||
|
import com.cloud.storage.GuestOsCategory;
|
||||||
|
import com.cloud.storage.VMTemplateVO;
|
||||||
|
import com.cloud.usage.UsageVO;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.user.AccountManager;
|
||||||
|
import com.cloud.user.AccountVO;
|
||||||
|
import com.cloud.user.User;
|
||||||
|
import com.cloud.user.UserData;
|
||||||
|
import com.cloud.user.UserDataVO;
|
||||||
|
import com.cloud.user.UserVO;
|
||||||
|
import com.cloud.user.dao.UserDataDao;
|
||||||
|
import com.cloud.utils.net.Ip;
|
||||||
|
import com.cloud.vm.NicSecondaryIp;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class ApiResponseHelperTest {
|
public class ApiResponseHelperTest {
|
||||||
@ -105,6 +121,9 @@ public class ApiResponseHelperTest {
|
|||||||
@Mock
|
@Mock
|
||||||
IPAddressDao ipAddressDaoMock;
|
IPAddressDao ipAddressDaoMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
ResourceIconManager resourceIconManager;
|
||||||
|
|
||||||
@Spy
|
@Spy
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
ApiResponseHelper apiResponseHelper = new ApiResponseHelper();
|
ApiResponseHelper apiResponseHelper = new ApiResponseHelper();
|
||||||
@ -481,4 +500,135 @@ public class ApiResponseHelperTest {
|
|||||||
Assert.assertTrue(apiResponseHelper.capacityListingForSingleNonGpuType(List.of(c1, c2)));
|
Assert.assertTrue(apiResponseHelper.capacityListingForSingleNonGpuType(List.of(c1, c2)));
|
||||||
Assert.assertFalse(apiResponseHelper.capacityListingForSingleNonGpuType(List.of(c1, c2, c3)));
|
Assert.assertFalse(apiResponseHelper.capacityListingForSingleNonGpuType(List.of(c1, c2, c3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateGuestOSCategoryResponse_WithResourceIcon() {
|
||||||
|
GuestOsCategory guestOsCategory = Mockito.mock(GuestOsCategory.class);
|
||||||
|
ResourceIconVO resourceIconVO = Mockito.mock(ResourceIconVO.class);
|
||||||
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
String name = "Ubuntu";
|
||||||
|
boolean featured = true;
|
||||||
|
Mockito.when(guestOsCategory.getUuid()).thenReturn(uuid);
|
||||||
|
Mockito.when(guestOsCategory.getName()).thenReturn(name);
|
||||||
|
Mockito.when(guestOsCategory.isFeatured()).thenReturn(featured);
|
||||||
|
ResourceIconResponse mockIconResponse = Mockito.mock(ResourceIconResponse.class);
|
||||||
|
try (MockedStatic<ApiDBUtils> ignored = Mockito.mockStatic(ApiDBUtils.class)) {
|
||||||
|
Mockito.when(ApiDBUtils.getResourceIconByResourceUUID(uuid, ResourceTag.ResourceObjectType.GuestOsCategory)).thenReturn(resourceIconVO);
|
||||||
|
Mockito.when(ApiDBUtils.newResourceIconResponse(resourceIconVO)).thenReturn(mockIconResponse);
|
||||||
|
GuestOSCategoryResponse response = apiResponseHelper.createGuestOSCategoryResponse(guestOsCategory);
|
||||||
|
Assert.assertNotNull(response);
|
||||||
|
Assert.assertEquals(uuid, response.getId());
|
||||||
|
Assert.assertEquals(name, response.getName());
|
||||||
|
Object obj = ReflectionTestUtils.getField(response, "featured");
|
||||||
|
if (obj == null) {
|
||||||
|
Assert.fail("Invalid featured value");
|
||||||
|
}
|
||||||
|
Assert.assertTrue((Boolean)obj);
|
||||||
|
obj = ReflectionTestUtils.getField(response, "resourceIconResponse");
|
||||||
|
Assert.assertNotNull(obj);
|
||||||
|
Assert.assertEquals("oscategory", response.getObjectName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateGuestOSCategoryResponse_WithoutResourceIcon() {
|
||||||
|
GuestOsCategory guestOsCategory = Mockito.mock(GuestOsCategory.class);
|
||||||
|
String uuid = "1234";
|
||||||
|
String name = "Ubuntu";
|
||||||
|
boolean featured = false;
|
||||||
|
Mockito.when(guestOsCategory.getUuid()).thenReturn(uuid);
|
||||||
|
Mockito.when(guestOsCategory.getName()).thenReturn(name);
|
||||||
|
Mockito.when(guestOsCategory.isFeatured()).thenReturn(featured);
|
||||||
|
try (MockedStatic<ApiDBUtils> ignored = Mockito.mockStatic(ApiDBUtils.class)) {
|
||||||
|
when(ApiDBUtils.getResourceIconByResourceUUID(uuid, ResourceTag.ResourceObjectType.GuestOsCategory)).thenReturn(null);
|
||||||
|
GuestOSCategoryResponse response = apiResponseHelper.createGuestOSCategoryResponse(guestOsCategory);
|
||||||
|
Assert.assertNotNull(response);
|
||||||
|
Assert.assertEquals(uuid, response.getId());
|
||||||
|
Assert.assertEquals(name, response.getName());
|
||||||
|
Object obj = ReflectionTestUtils.getField(response, "featured");
|
||||||
|
if (obj == null) {
|
||||||
|
Assert.fail("Invalid featured value");
|
||||||
|
}
|
||||||
|
Assert.assertFalse((Boolean)obj);
|
||||||
|
obj = ReflectionTestUtils.getField(response, "resourceIconResponse");
|
||||||
|
Assert.assertNull(obj);
|
||||||
|
Assert.assertEquals("oscategory", response.getObjectName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateGuestOSCategoryResponse_WithShowIconFalse() {
|
||||||
|
GuestOsCategory guestOsCategory = Mockito.mock(GuestOsCategory.class);
|
||||||
|
Mockito.when(guestOsCategory.getUuid()).thenReturn(UUID.randomUUID().toString());
|
||||||
|
try (MockedStatic<ApiDBUtils> mockedStatic = Mockito.mockStatic(ApiDBUtils.class)) {
|
||||||
|
GuestOSCategoryResponse response = apiResponseHelper.createGuestOSCategoryResponse(guestOsCategory, false);
|
||||||
|
Assert.assertNotNull(response);
|
||||||
|
mockedStatic.verify(() -> ApiDBUtils.getResourceIconByResourceUUID(Mockito.any(), Mockito.any()),
|
||||||
|
Mockito.never());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResourceIconsUsingOsCategory_withValidData() {
|
||||||
|
TemplateResponse template1 = Mockito.mock(TemplateResponse.class);
|
||||||
|
when(template1.getId()).thenReturn("t1");
|
||||||
|
when(template1.getOsTypeCategoryId()).thenReturn(100L);
|
||||||
|
TemplateResponse template2 = Mockito.mock(TemplateResponse.class);
|
||||||
|
when(template2.getId()).thenReturn("t2");
|
||||||
|
when(template2.getOsTypeCategoryId()).thenReturn(200L);
|
||||||
|
List<TemplateResponse> responses = Arrays.asList(template1, template2);
|
||||||
|
Map<Long, ResourceIcon> icons = new HashMap<>();
|
||||||
|
ResourceIcon icon1 = Mockito.mock(ResourceIcon.class);
|
||||||
|
ResourceIcon icon2 = Mockito.mock(ResourceIcon.class);
|
||||||
|
icons.put(100L, icon1);
|
||||||
|
icons.put(200L, icon2);
|
||||||
|
when(resourceIconManager.getByResourceTypeAndIds(Mockito.eq(ResourceTag.ResourceObjectType.GuestOsCategory), Mockito.anySet()))
|
||||||
|
.thenReturn(icons);
|
||||||
|
Map<String, ResourceIcon> result = apiResponseHelper.getResourceIconsUsingOsCategory(responses);
|
||||||
|
assertEquals(2, result.size());
|
||||||
|
assertEquals(icon1, result.get("t1"));
|
||||||
|
assertEquals(icon2, result.get("t2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResourceIconsUsingOsCategory_missingIcons() {
|
||||||
|
TemplateResponse template1 = Mockito.mock(TemplateResponse.class);
|
||||||
|
when(template1.getId()).thenReturn("t1");
|
||||||
|
when(template1.getOsTypeCategoryId()).thenReturn(100L);
|
||||||
|
List<TemplateResponse> responses = List.of(template1);
|
||||||
|
when(resourceIconManager.getByResourceTypeAndIds(Mockito.eq(ResourceTag.ResourceObjectType.GuestOsCategory), Mockito.anySet())).thenReturn(Collections.emptyMap());
|
||||||
|
Map<String, ResourceIcon> result = apiResponseHelper.getResourceIconsUsingOsCategory(responses);
|
||||||
|
assertTrue(result.containsKey("t1"));
|
||||||
|
assertNull(result.get("t1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateTemplateIsoResponsesForIcons_withMixedIcons() {
|
||||||
|
TemplateResponse template1 = Mockito.mock(TemplateResponse.class);
|
||||||
|
when(template1.getId()).thenReturn("t1");
|
||||||
|
TemplateResponse template2 = Mockito.mock(TemplateResponse.class);
|
||||||
|
when(template2.getId()).thenReturn("t2");
|
||||||
|
List<TemplateResponse> responses = Arrays.asList(template1, template2);
|
||||||
|
Map<String, ResourceIcon> isoIcons = new HashMap<>();
|
||||||
|
isoIcons.put("t1", Mockito.mock(ResourceIcon.class));
|
||||||
|
when(resourceIconManager.getByResourceTypeAndUuids(ResourceTag.ResourceObjectType.ISO, Set.of("t1", "t2")))
|
||||||
|
.thenReturn(isoIcons);
|
||||||
|
Map<String, ResourceIcon> fallbackIcons = Map.of("t2", Mockito.mock(ResourceIcon.class));
|
||||||
|
Mockito.doReturn(fallbackIcons).when(apiResponseHelper).getResourceIconsUsingOsCategory(Mockito.anyList());
|
||||||
|
ResourceIconResponse iconResponse1 = new ResourceIconResponse();
|
||||||
|
ResourceIconResponse iconResponse2 = new ResourceIconResponse();
|
||||||
|
Mockito.doReturn(iconResponse1).when(apiResponseHelper).createResourceIconResponse(isoIcons.get("t1"));
|
||||||
|
Mockito.doReturn(iconResponse2).when(apiResponseHelper).createResourceIconResponse(fallbackIcons.get("t2"));
|
||||||
|
apiResponseHelper.updateTemplateIsoResponsesForIcons(responses, ResourceTag.ResourceObjectType.ISO);
|
||||||
|
verify(template1).setResourceIconResponse(iconResponse1);
|
||||||
|
verify(template2).setResourceIconResponse(iconResponse2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateTemplateIsoResponsesForIcons_emptyInput() {
|
||||||
|
apiResponseHelper.updateTemplateIsoResponsesForIcons(Collections.emptyList(),
|
||||||
|
ResourceTag.ResourceObjectType.Template);
|
||||||
|
Mockito.verify(resourceIconManager, Mockito.never()).getByResourceTypeAndUuids(Mockito.any(),
|
||||||
|
Mockito.anyCollection());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,56 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.server;
|
package com.cloud.server;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCategoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.DeleteGuestOsCategoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsCategoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.userdata.DeleteUserDataCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.userdata.ListUserDataCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.userdata.RegisterUserDataCmd;
|
||||||
|
import org.apache.cloudstack.config.Configuration;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigDepot;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
|
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
|
||||||
|
import org.apache.cloudstack.userdata.UserDataManager;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import com.cloud.cpu.CPU;
|
||||||
import com.cloud.dc.Vlan.VlanType;
|
import com.cloud.dc.Vlan.VlanType;
|
||||||
import com.cloud.domain.dao.DomainDao;
|
import com.cloud.domain.dao.DomainDao;
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
@ -26,7 +76,12 @@ import com.cloud.host.dao.HostDetailsDao;
|
|||||||
import com.cloud.network.IpAddress;
|
import com.cloud.network.IpAddress;
|
||||||
import com.cloud.network.IpAddressManagerImpl;
|
import com.cloud.network.IpAddressManagerImpl;
|
||||||
import com.cloud.network.dao.IPAddressVO;
|
import com.cloud.network.dao.IPAddressVO;
|
||||||
|
import com.cloud.storage.GuestOSCategoryVO;
|
||||||
|
import com.cloud.storage.GuestOSVO;
|
||||||
|
import com.cloud.storage.GuestOsCategory;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
|
import com.cloud.storage.dao.GuestOSCategoryDao;
|
||||||
|
import com.cloud.storage.dao.GuestOSDao;
|
||||||
import com.cloud.storage.dao.VMTemplateDao;
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
@ -46,46 +101,6 @@ import com.cloud.vm.UserVmDetailVO;
|
|||||||
import com.cloud.vm.UserVmVO;
|
import com.cloud.vm.UserVmVO;
|
||||||
import com.cloud.vm.dao.UserVmDao;
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
import com.cloud.vm.dao.UserVmDetailsDao;
|
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
|
||||||
import org.apache.cloudstack.api.BaseCmd;
|
|
||||||
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
|
||||||
import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd;
|
|
||||||
import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd;
|
|
||||||
import org.apache.cloudstack.api.command.user.userdata.DeleteUserDataCmd;
|
|
||||||
import org.apache.cloudstack.api.command.user.userdata.ListUserDataCmd;
|
|
||||||
import org.apache.cloudstack.api.command.user.userdata.RegisterUserDataCmd;
|
|
||||||
import org.apache.cloudstack.config.Configuration;
|
|
||||||
import org.apache.cloudstack.context.CallContext;
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
|
|
||||||
import org.apache.cloudstack.framework.config.ConfigDepot;
|
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
|
||||||
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
|
|
||||||
import org.apache.cloudstack.userdata.UserDataManager;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockedStatic;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.mockito.Spy;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.ArgumentMatchers.nullable;
|
|
||||||
import static org.mockito.Mockito.any;
|
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class ManagementServerImplTest {
|
public class ManagementServerImplTest {
|
||||||
@ -118,7 +133,7 @@ public class ManagementServerImplTest {
|
|||||||
UserDataDao _userDataDao;
|
UserDataDao _userDataDao;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
VMTemplateDao _templateDao;
|
VMTemplateDao templateDao;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
AnnotationDao annotationDao;
|
AnnotationDao annotationDao;
|
||||||
@ -129,9 +144,6 @@ public class ManagementServerImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
UserDataManager userDataManager;
|
UserDataManager userDataManager;
|
||||||
|
|
||||||
@Spy
|
|
||||||
ManagementServerImpl spy = new ManagementServerImpl();
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
UserVmDetailsDao userVmDetailsDao;
|
UserVmDetailsDao userVmDetailsDao;
|
||||||
|
|
||||||
@ -147,23 +159,22 @@ public class ManagementServerImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
DomainDao domainDao;
|
DomainDao domainDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
GuestOSCategoryDao _guestOSCategoryDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
GuestOSDao _guestOSDao;
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
@InjectMocks
|
||||||
|
ManagementServerImpl spy = new ManagementServerImpl();
|
||||||
|
|
||||||
private AutoCloseable closeable;
|
private AutoCloseable closeable;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws IllegalAccessException, NoSuchFieldException {
|
public void setup() throws IllegalAccessException, NoSuchFieldException {
|
||||||
closeable = MockitoAnnotations.openMocks(this);
|
closeable = MockitoAnnotations.openMocks(this);
|
||||||
CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class));
|
CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class));
|
||||||
spy._accountMgr = _accountMgr;
|
|
||||||
spy.userDataDao = _userDataDao;
|
|
||||||
spy.templateDao = _templateDao;
|
|
||||||
spy._userVmDao = _userVmDao;
|
|
||||||
spy.annotationDao = annotationDao;
|
|
||||||
spy._UserVmDetailsDao = userVmDetailsDao;
|
|
||||||
spy._detailsDao = hostDetailsDao;
|
|
||||||
spy.userDataManager = userDataManager;
|
|
||||||
spy._configDao = configDao;
|
|
||||||
spy._configDepot = configDepot;
|
|
||||||
spy._domainDao = domainDao;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@ -407,7 +418,7 @@ public class ManagementServerImplTest {
|
|||||||
|
|
||||||
Mockito.when(userData.getId()).thenReturn(1L);
|
Mockito.when(userData.getId()).thenReturn(1L);
|
||||||
when(_userDataDao.findById(1L)).thenReturn(userData);
|
when(_userDataDao.findById(1L)).thenReturn(userData);
|
||||||
when(_templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(new ArrayList<VMTemplateVO>());
|
when(templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(new ArrayList<VMTemplateVO>());
|
||||||
when(_userVmDao.findByUserDataId(1L)).thenReturn(new ArrayList<UserVmVO>());
|
when(_userVmDao.findByUserDataId(1L)).thenReturn(new ArrayList<UserVmVO>());
|
||||||
when(_userDataDao.remove(1L)).thenReturn(true);
|
when(_userDataDao.remove(1L)).thenReturn(true);
|
||||||
|
|
||||||
@ -437,7 +448,7 @@ public class ManagementServerImplTest {
|
|||||||
VMTemplateVO vmTemplateVO = Mockito.mock(VMTemplateVO.class);
|
VMTemplateVO vmTemplateVO = Mockito.mock(VMTemplateVO.class);
|
||||||
List<VMTemplateVO> linkedTemplates = new ArrayList<>();
|
List<VMTemplateVO> linkedTemplates = new ArrayList<>();
|
||||||
linkedTemplates.add(vmTemplateVO);
|
linkedTemplates.add(vmTemplateVO);
|
||||||
when(_templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(linkedTemplates);
|
when(templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(linkedTemplates);
|
||||||
|
|
||||||
spy.deleteUserData(cmd);
|
spy.deleteUserData(cmd);
|
||||||
}
|
}
|
||||||
@ -461,7 +472,7 @@ public class ManagementServerImplTest {
|
|||||||
Mockito.when(userData.getId()).thenReturn(1L);
|
Mockito.when(userData.getId()).thenReturn(1L);
|
||||||
when(_userDataDao.findById(1L)).thenReturn(userData);
|
when(_userDataDao.findById(1L)).thenReturn(userData);
|
||||||
|
|
||||||
when(_templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(new ArrayList<VMTemplateVO>());
|
when(templateDao.findTemplatesLinkedToUserdata(1L)).thenReturn(new ArrayList<VMTemplateVO>());
|
||||||
|
|
||||||
UserVmVO userVmVO = Mockito.mock(UserVmVO.class);
|
UserVmVO userVmVO = Mockito.mock(UserVmVO.class);
|
||||||
List<UserVmVO> vms = new ArrayList<>();
|
List<UserVmVO> vms = new ArrayList<>();
|
||||||
@ -740,4 +751,272 @@ public class ManagementServerImplTest {
|
|||||||
|
|
||||||
Assert.assertEquals("0.85", result.first().get(0).getValue());
|
Assert.assertEquals("0.85", result.first().get(0).getValue());
|
||||||
}
|
}
|
||||||
|
@Test
|
||||||
|
public void testAddGuestOsCategory() {
|
||||||
|
AddGuestOsCategoryCmd addCmd = Mockito.mock(AddGuestOsCategoryCmd.class);
|
||||||
|
String name = "Ubuntu";
|
||||||
|
boolean featured = true;
|
||||||
|
Mockito.when(addCmd.getName()).thenReturn(name);
|
||||||
|
Mockito.when(addCmd.isFeatured()).thenReturn(featured);
|
||||||
|
Mockito.doAnswer((Answer<GuestOSCategoryVO>) invocation -> (GuestOSCategoryVO)invocation.getArguments()[0]).when(_guestOSCategoryDao).persist(Mockito.any(GuestOSCategoryVO.class));
|
||||||
|
GuestOsCategory result = spy.addGuestOsCategory(addCmd);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertEquals(name, result.getName());
|
||||||
|
Assert.assertEquals(featured, result.isFeatured());
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).persist(any(GuestOSCategoryVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateGuestOsCategory() {
|
||||||
|
UpdateGuestOsCategoryCmd updateCmd = Mockito.mock(UpdateGuestOsCategoryCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = new GuestOSCategoryVO("Old name", false);
|
||||||
|
long id = 1L;
|
||||||
|
String name = "Updated Name";
|
||||||
|
Boolean featured = true;
|
||||||
|
Integer sortKey = 10;
|
||||||
|
Mockito.when(updateCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(updateCmd.getName()).thenReturn(name);
|
||||||
|
Mockito.when(updateCmd.isFeatured()).thenReturn(featured);
|
||||||
|
Mockito.when(updateCmd.getSortKey()).thenReturn(sortKey);
|
||||||
|
Mockito.when(_guestOSCategoryDao.findById(id)).thenReturn(guestOSCategory);
|
||||||
|
Mockito.when(_guestOSCategoryDao.update(Mockito.eq(id), any(GuestOSCategoryVO.class))).thenReturn(true);
|
||||||
|
GuestOsCategory result = spy.updateGuestOsCategory(updateCmd);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertEquals(name, result.getName());
|
||||||
|
Assert.assertEquals(featured, result.isFeatured());
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).findById(id);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).update(Mockito.eq(id), any(GuestOSCategoryVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testUpdateGuestOsCategory_ThrowsExceptionWhenCategoryNotFound() {
|
||||||
|
UpdateGuestOsCategoryCmd updateCmd = Mockito.mock(UpdateGuestOsCategoryCmd.class);
|
||||||
|
long id = 1L;
|
||||||
|
when(updateCmd.getId()).thenReturn(id);
|
||||||
|
when(_guestOSCategoryDao.findById(id)).thenReturn(null);
|
||||||
|
spy.updateGuestOsCategory(updateCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateGuestOsCategory_NoChanges() {
|
||||||
|
UpdateGuestOsCategoryCmd updateCmd = Mockito.mock(UpdateGuestOsCategoryCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = new GuestOSCategoryVO("Old name", false);
|
||||||
|
long id = 1L;
|
||||||
|
when(updateCmd.getId()).thenReturn(id);
|
||||||
|
when(updateCmd.getName()).thenReturn(null);
|
||||||
|
when(updateCmd.isFeatured()).thenReturn(null);
|
||||||
|
when(updateCmd.getSortKey()).thenReturn(null);
|
||||||
|
when(_guestOSCategoryDao.findById(id)).thenReturn(guestOSCategory);
|
||||||
|
GuestOsCategory result = spy.updateGuestOsCategory(updateCmd);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertNotNull(result.getName());
|
||||||
|
Assert.assertFalse(result.isFeatured());
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).findById(id);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.never()).update(Mockito.eq(id), any(GuestOSCategoryVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateGuestOsCategory_UpdateNameOnly() {
|
||||||
|
UpdateGuestOsCategoryCmd updateCmd = Mockito.mock(UpdateGuestOsCategoryCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = new GuestOSCategoryVO("Old name", false);
|
||||||
|
long id = 1L;
|
||||||
|
String name = "Updated Name";
|
||||||
|
Mockito.when(updateCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(updateCmd.getName()).thenReturn(name);
|
||||||
|
Mockito.when(updateCmd.isFeatured()).thenReturn(null);
|
||||||
|
Mockito.when(updateCmd.getSortKey()).thenReturn(null);
|
||||||
|
Mockito.when(_guestOSCategoryDao.findById(id)).thenReturn(guestOSCategory);
|
||||||
|
Mockito.when(_guestOSCategoryDao.update(Mockito.eq(id), any(GuestOSCategoryVO.class))).thenReturn(true);
|
||||||
|
GuestOsCategory result = spy.updateGuestOsCategory(updateCmd);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertEquals(name, result.getName());
|
||||||
|
Assert.assertFalse(result.isFeatured());
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).findById(id);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).update(Mockito.eq(id), any(GuestOSCategoryVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteGuestOsCategory_Successful() {
|
||||||
|
DeleteGuestOsCategoryCmd deleteCmd = Mockito.mock(DeleteGuestOsCategoryCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = Mockito.mock(GuestOSCategoryVO.class);
|
||||||
|
long id = 1L;
|
||||||
|
Mockito.when(deleteCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(_guestOSCategoryDao.findById(id)).thenReturn(guestOSCategory);
|
||||||
|
Mockito.when(_guestOSDao.listIdsByCategoryId(id)).thenReturn(Arrays.asList());
|
||||||
|
Mockito.when(_guestOSCategoryDao.remove(id)).thenReturn(true);
|
||||||
|
boolean result = spy.deleteGuestOsCategory(deleteCmd);
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).findById(id);
|
||||||
|
Mockito.verify(_guestOSDao, Mockito.times(1)).listIdsByCategoryId(id);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testDeleteGuestOsCategory_ThrowsExceptionWhenCategoryNotFound() {
|
||||||
|
DeleteGuestOsCategoryCmd deleteCmd = Mockito.mock(DeleteGuestOsCategoryCmd.class);
|
||||||
|
long id = 1L;
|
||||||
|
Mockito.when(deleteCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(_guestOSCategoryDao.findById(id)).thenReturn(null);
|
||||||
|
spy.deleteGuestOsCategory(deleteCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testDeleteGuestOsCategory_ThrowsExceptionWhenGuestOsExists() {
|
||||||
|
DeleteGuestOsCategoryCmd deleteCmd = Mockito.mock(DeleteGuestOsCategoryCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = Mockito.mock(GuestOSCategoryVO.class);
|
||||||
|
long id = 1L;
|
||||||
|
Mockito.when(deleteCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(_guestOSCategoryDao.findById(id)).thenReturn(guestOSCategory);
|
||||||
|
Mockito.when(_guestOSDao.listIdsByCategoryId(id)).thenReturn(Arrays.asList(1L));
|
||||||
|
spy.deleteGuestOsCategory(deleteCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockGuestOsJoin() {
|
||||||
|
GuestOSVO vo = mock(GuestOSVO.class);
|
||||||
|
SearchBuilder<GuestOSVO> sb = mock(SearchBuilder.class);
|
||||||
|
when(sb.entity()).thenReturn(vo);
|
||||||
|
when(_guestOSDao.createSearchBuilder()).thenReturn(sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListGuestOSCategoriesByCriteria_Success() {
|
||||||
|
ListGuestOsCategoriesCmd listCmd = Mockito.mock(ListGuestOsCategoriesCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = Mockito.mock(GuestOSCategoryVO.class);
|
||||||
|
Filter filter = Mockito.mock(Filter.class);
|
||||||
|
Long id = 1L;
|
||||||
|
String name = "Ubuntu";
|
||||||
|
String keyword = "Linux";
|
||||||
|
Boolean featured = true;
|
||||||
|
Long zoneId = 1L;
|
||||||
|
CPU.CPUArch arch = CPU.CPUArch.getDefault();
|
||||||
|
Boolean isIso = true;
|
||||||
|
Boolean isVnf = false;
|
||||||
|
Mockito.when(listCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(listCmd.getName()).thenReturn(name);
|
||||||
|
Mockito.when(listCmd.getKeyword()).thenReturn(keyword);
|
||||||
|
Mockito.when(listCmd.isFeatured()).thenReturn(featured);
|
||||||
|
Mockito.when(listCmd.getZoneId()).thenReturn(zoneId);
|
||||||
|
Mockito.when(listCmd.getArch()).thenReturn(arch);
|
||||||
|
Mockito.when(listCmd.isIso()).thenReturn(isIso);
|
||||||
|
Mockito.when(listCmd.isVnf()).thenReturn(isVnf);
|
||||||
|
SearchBuilder<GuestOSCategoryVO> searchBuilder = Mockito.mock(SearchBuilder.class);
|
||||||
|
Mockito.when(searchBuilder.entity()).thenReturn(guestOSCategory);
|
||||||
|
SearchCriteria<GuestOSCategoryVO> searchCriteria = Mockito.mock(SearchCriteria.class);
|
||||||
|
Mockito.when(_guestOSCategoryDao.createSearchBuilder()).thenReturn(searchBuilder);
|
||||||
|
Mockito.when(searchBuilder.create()).thenReturn(searchCriteria);
|
||||||
|
Mockito.when(templateDao.listTemplateIsoByArchVnfAndZone(zoneId, arch, isIso, isVnf)).thenReturn(Arrays.asList(1L, 2L));
|
||||||
|
Pair<List<GuestOSCategoryVO>, Integer> mockResult = new Pair<>(Arrays.asList(guestOSCategory), 1);
|
||||||
|
mockGuestOsJoin();
|
||||||
|
Mockito.when(_guestOSCategoryDao.searchAndCount(Mockito.eq(searchCriteria), Mockito.any())).thenReturn(mockResult);
|
||||||
|
Pair<List<? extends GuestOsCategory>, Integer> result = spy.listGuestOSCategoriesByCriteria(listCmd);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertEquals(1, result.second().intValue());
|
||||||
|
Assert.assertEquals(1, result.first().size());
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).createSearchBuilder();
|
||||||
|
Mockito.verify(templateDao, Mockito.times(1)).listTemplateIsoByArchVnfAndZone(zoneId, arch, isIso, isVnf);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).searchAndCount(Mockito.eq(searchCriteria), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListGuestOSCategoriesByCriteria_NoResults() {
|
||||||
|
ListGuestOsCategoriesCmd listCmd = Mockito.mock(ListGuestOsCategoriesCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = Mockito.mock(GuestOSCategoryVO.class);
|
||||||
|
Long id = 1L;
|
||||||
|
String name = "CentOS";
|
||||||
|
String keyword = "Linux";
|
||||||
|
Boolean featured = false;
|
||||||
|
Long zoneId = 1L;
|
||||||
|
CPU.CPUArch arch = CPU.CPUArch.getDefault();
|
||||||
|
Boolean isIso = false;
|
||||||
|
Boolean isVnf = false;
|
||||||
|
Mockito.when(listCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(listCmd.getName()).thenReturn(name);
|
||||||
|
Mockito.when(listCmd.getKeyword()).thenReturn(keyword);
|
||||||
|
Mockito.when(listCmd.isFeatured()).thenReturn(featured);
|
||||||
|
Mockito.when(listCmd.getZoneId()).thenReturn(zoneId);
|
||||||
|
Mockito.when(listCmd.getArch()).thenReturn(arch);
|
||||||
|
Mockito.when(listCmd.isIso()).thenReturn(isIso);
|
||||||
|
Mockito.when(listCmd.isVnf()).thenReturn(isVnf);
|
||||||
|
SearchBuilder<GuestOSCategoryVO> searchBuilder = Mockito.mock(SearchBuilder.class);
|
||||||
|
Mockito.when(searchBuilder.entity()).thenReturn(guestOSCategory);
|
||||||
|
SearchCriteria<GuestOSCategoryVO> searchCriteria = Mockito.mock(SearchCriteria.class);
|
||||||
|
Mockito.when(_guestOSCategoryDao.createSearchBuilder()).thenReturn(searchBuilder);
|
||||||
|
Mockito.when(searchBuilder.create()).thenReturn(searchCriteria);
|
||||||
|
Mockito.when(templateDao.listTemplateIsoByArchVnfAndZone(zoneId, arch, isIso, isVnf)).thenReturn(Arrays.asList(1L, 2L));
|
||||||
|
Pair<List<GuestOSCategoryVO>, Integer> mockResult = new Pair<>(Arrays.asList(), 0);
|
||||||
|
Mockito.when(_guestOSCategoryDao.searchAndCount(Mockito.eq(searchCriteria), Mockito.any())).thenReturn(mockResult);
|
||||||
|
mockGuestOsJoin();
|
||||||
|
Pair<List<? extends GuestOsCategory>, Integer> result = spy.listGuestOSCategoriesByCriteria(listCmd);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertEquals(0, result.second().intValue());
|
||||||
|
Assert.assertEquals(0, result.first().size());
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).createSearchBuilder();
|
||||||
|
Mockito.verify(templateDao, Mockito.times(1)).listTemplateIsoByArchVnfAndZone(zoneId, arch, isIso, isVnf);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).searchAndCount(Mockito.eq(searchCriteria), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListGuestOSCategoriesByCriteria_NoGuestOsIdsFound() {
|
||||||
|
ListGuestOsCategoriesCmd listCmd = Mockito.mock(ListGuestOsCategoriesCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = Mockito.mock(GuestOSCategoryVO.class);
|
||||||
|
Long id = 1L;
|
||||||
|
String name = "Ubuntu";
|
||||||
|
String keyword = "Linux";
|
||||||
|
Boolean featured = true;
|
||||||
|
Long zoneId = 1L;
|
||||||
|
CPU.CPUArch arch = CPU.CPUArch.getDefault();
|
||||||
|
Boolean isIso = true;
|
||||||
|
Boolean isVnf = false;
|
||||||
|
Mockito.when(listCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(listCmd.getName()).thenReturn(name);
|
||||||
|
Mockito.when(listCmd.getKeyword()).thenReturn(keyword);
|
||||||
|
Mockito.when(listCmd.isFeatured()).thenReturn(featured);
|
||||||
|
Mockito.when(listCmd.getZoneId()).thenReturn(zoneId);
|
||||||
|
Mockito.when(listCmd.getArch()).thenReturn(arch);
|
||||||
|
Mockito.when(listCmd.isIso()).thenReturn(isIso);
|
||||||
|
Mockito.when(listCmd.isVnf()).thenReturn(isVnf);
|
||||||
|
SearchBuilder<GuestOSCategoryVO> searchBuilder = Mockito.mock(SearchBuilder.class);
|
||||||
|
Mockito.when(searchBuilder.entity()).thenReturn(guestOSCategory);
|
||||||
|
SearchCriteria<GuestOSCategoryVO> searchCriteria = Mockito.mock(SearchCriteria.class);
|
||||||
|
Mockito.when(_guestOSCategoryDao.createSearchBuilder()).thenReturn(searchBuilder);
|
||||||
|
Mockito.when(searchBuilder.create()).thenReturn(searchCriteria);
|
||||||
|
Mockito.when(templateDao.listTemplateIsoByArchVnfAndZone(zoneId, arch, isIso, isVnf)).thenReturn(Arrays.asList(1L, 2L));
|
||||||
|
Pair<List<GuestOSCategoryVO>, Integer> mockResult = new Pair<>(Arrays.asList(), 0);
|
||||||
|
when(_guestOSCategoryDao.searchAndCount(Mockito.eq(searchCriteria), Mockito.any())).thenReturn(mockResult);
|
||||||
|
mockGuestOsJoin();
|
||||||
|
Pair<List<? extends GuestOsCategory>, Integer> result = spy.listGuestOSCategoriesByCriteria(listCmd);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertEquals(0, result.second().intValue());
|
||||||
|
Assert.assertEquals(0, result.first().size());
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).createSearchBuilder();
|
||||||
|
Mockito.verify(templateDao, Mockito.times(1)).listTemplateIsoByArchVnfAndZone(zoneId, arch, isIso, isVnf);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).searchAndCount(Mockito.eq(searchCriteria), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListGuestOSCategoriesByCriteria_FilterById() {
|
||||||
|
ListGuestOsCategoriesCmd listCmd = Mockito.mock(ListGuestOsCategoriesCmd.class);
|
||||||
|
GuestOSCategoryVO guestOSCategory = Mockito.mock(GuestOSCategoryVO.class);
|
||||||
|
Long id = 1L;
|
||||||
|
Mockito.when(listCmd.getId()).thenReturn(id);
|
||||||
|
Mockito.when(listCmd.getZoneId()).thenReturn(null);
|
||||||
|
Mockito.when(listCmd.isIso()).thenReturn(null);
|
||||||
|
Mockito.when(listCmd.isVnf()).thenReturn(null);
|
||||||
|
SearchBuilder<GuestOSCategoryVO> searchBuilder = Mockito.mock(SearchBuilder.class);
|
||||||
|
Mockito.when(searchBuilder.entity()).thenReturn(guestOSCategory);
|
||||||
|
SearchCriteria<GuestOSCategoryVO> searchCriteria = Mockito.mock(SearchCriteria.class);
|
||||||
|
Mockito.when(_guestOSCategoryDao.createSearchBuilder()).thenReturn(searchBuilder);
|
||||||
|
Mockito.when(searchBuilder.create()).thenReturn(searchCriteria);
|
||||||
|
Pair<List<GuestOSCategoryVO>, Integer> mockResult = new Pair<>(Arrays.asList(guestOSCategory), 1);
|
||||||
|
Mockito.when(_guestOSCategoryDao.searchAndCount(Mockito.eq(searchCriteria), Mockito.any())).thenReturn(mockResult);
|
||||||
|
mockGuestOsJoin();
|
||||||
|
Pair<List<? extends GuestOsCategory>, Integer> result = spy.listGuestOSCategoriesByCriteria(listCmd);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertEquals(1, result.second().intValue());
|
||||||
|
Assert.assertEquals(1, result.first().size());
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).createSearchBuilder();
|
||||||
|
Mockito.verify(searchCriteria, Mockito.times(1)).setParameters("id", id);
|
||||||
|
Mockito.verify(_guestOSCategoryDao, Mockito.times(1)).searchAndCount(Mockito.eq(searchCriteria), Mockito.any());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
ui/public/config.json
vendored
3
ui/public/config.json
vendored
@ -97,5 +97,8 @@
|
|||||||
"basicZoneEnabled": true,
|
"basicZoneEnabled": true,
|
||||||
"multipleServer": false,
|
"multipleServer": false,
|
||||||
"allowSettingTheme": true,
|
"allowSettingTheme": true,
|
||||||
|
"imageSelectionInterface": "modern",
|
||||||
|
"showUserCategoryForModernImageSelection": true,
|
||||||
|
"showAllCategoryForModernImageSelection": false,
|
||||||
"docHelpMappings": {}
|
"docHelpMappings": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,8 +87,9 @@
|
|||||||
"label.action.delete.egress.firewall": "Delete egress firewall rule",
|
"label.action.delete.egress.firewall": "Delete egress firewall rule",
|
||||||
"label.action.delete.firewall": "Delete firewall rule",
|
"label.action.delete.firewall": "Delete firewall rule",
|
||||||
"label.action.delete.interface.static.route": "Remove Tungsten Fabric interface static route",
|
"label.action.delete.interface.static.route": "Remove Tungsten Fabric interface static route",
|
||||||
"label.action.delete.guest.os": "Delete guest os",
|
"label.action.delete.guest.os": "Delete guest OS",
|
||||||
"label.action.delete.guest.os.hypervisor.mapping": "Delete guest os hypervisor mapping",
|
"label.action.delete.guest.os.category": "Delete guest OS category",
|
||||||
|
"label.action.delete.guest.os.hypervisor.mapping": "Delete guest OS hypervisor mapping",
|
||||||
"label.action.delete.ip.range": "Delete IP range",
|
"label.action.delete.ip.range": "Delete IP range",
|
||||||
"label.action.delete.iso": "Delete ISO",
|
"label.action.delete.iso": "Delete ISO",
|
||||||
"label.action.delete.load.balancer": "Delete load balancer rule",
|
"label.action.delete.load.balancer": "Delete load balancer rule",
|
||||||
@ -263,8 +264,9 @@
|
|||||||
"label.add.firewall": "Add firewall rule",
|
"label.add.firewall": "Add firewall rule",
|
||||||
"label.add.firewallrule": "Add Firewall Rule",
|
"label.add.firewallrule": "Add Firewall Rule",
|
||||||
"label.add.guest.network": "Add guest Network",
|
"label.add.guest.network": "Add guest Network",
|
||||||
"label.add.guest.os": "Add guest os",
|
"label.add.guest.os": "Add guest OS",
|
||||||
"label.add.guest.os.hypervisor.mapping": "Add guest os hypervisor mapping",
|
"label.add.guest.os.category": "Add guest OS category",
|
||||||
|
"label.add.guest.os.hypervisor.mapping": "Add guest OS hypervisor mapping",
|
||||||
"label.add.host": "Add host",
|
"label.add.host": "Add host",
|
||||||
"label.add.ingress.rule": "Add ingress rule",
|
"label.add.ingress.rule": "Add ingress rule",
|
||||||
"label.add.intermediate.certificate": "Add intermediate certificate",
|
"label.add.intermediate.certificate": "Add intermediate certificate",
|
||||||
@ -1069,6 +1071,8 @@
|
|||||||
"label.guest.netmask": "Guest netmask",
|
"label.guest.netmask": "Guest netmask",
|
||||||
"label.guest.networks": "Guest Networks",
|
"label.guest.networks": "Guest Networks",
|
||||||
"label.guest.os": "Guest OS",
|
"label.guest.os": "Guest OS",
|
||||||
|
"label.guest.os.category": "Guest OS Category",
|
||||||
|
"label.guest.os.categories": "Guest OS Categories",
|
||||||
"label.guest.os.hypervisor.mappings": "Guest OS mappings",
|
"label.guest.os.hypervisor.mappings": "Guest OS mappings",
|
||||||
"label.guest.start.ip": "Guest start IP",
|
"label.guest.start.ip": "Guest start IP",
|
||||||
"label.guest.traffic": "Guest traffic",
|
"label.guest.traffic": "Guest traffic",
|
||||||
@ -1143,6 +1147,8 @@
|
|||||||
"label.ikelifetime": "IKE lifetime (second)",
|
"label.ikelifetime": "IKE lifetime (second)",
|
||||||
"label.ikepolicy": "IKE policy",
|
"label.ikepolicy": "IKE policy",
|
||||||
"label.ikeversion": "IKE version",
|
"label.ikeversion": "IKE version",
|
||||||
|
"label.image": "Image",
|
||||||
|
"label.image.type": "Image type",
|
||||||
"label.images": "Images",
|
"label.images": "Images",
|
||||||
"label.imagestoreid": "Secondary Storage",
|
"label.imagestoreid": "Secondary Storage",
|
||||||
"label.import.backup.offering": "Import backup offering",
|
"label.import.backup.offering": "Import backup offering",
|
||||||
@ -1651,6 +1657,7 @@
|
|||||||
"label.operator.equal": "Equals to",
|
"label.operator.equal": "Equals to",
|
||||||
"label.optional": "Optional",
|
"label.optional": "Optional",
|
||||||
"label.order": "Order",
|
"label.order": "Order",
|
||||||
|
"label.os": "Operating System",
|
||||||
"label.oscategoryid": "OS category",
|
"label.oscategoryid": "OS category",
|
||||||
"label.oscategoryname": "OS category name",
|
"label.oscategoryname": "OS category name",
|
||||||
"label.osname": "OS name",
|
"label.osname": "OS name",
|
||||||
@ -1806,6 +1813,7 @@
|
|||||||
"label.provisioningtype.fat": "Fat provisioning",
|
"label.provisioningtype.fat": "Fat provisioning",
|
||||||
"label.provisioningtype.sparse": "Sparse provisioning",
|
"label.provisioningtype.sparse": "Sparse provisioning",
|
||||||
"label.provisioningtype.thin": "Thin provisioning",
|
"label.provisioningtype.thin": "Thin provisioning",
|
||||||
|
"label.public": "Public",
|
||||||
"label.publicmtu": "Public Interface MTU",
|
"label.publicmtu": "Public Interface MTU",
|
||||||
"label.public.interface": "Public interface",
|
"label.public.interface": "Public interface",
|
||||||
"label.public.ip": "Public IP address",
|
"label.public.ip": "Public IP address",
|
||||||
@ -2305,7 +2313,8 @@
|
|||||||
"label.tariffvalue": "Tariff value",
|
"label.tariffvalue": "Tariff value",
|
||||||
"label.tcp": "TCP",
|
"label.tcp": "TCP",
|
||||||
"label.tcp.proxy": "TCP proxy",
|
"label.tcp.proxy": "TCP proxy",
|
||||||
"label.template": "Select a template",
|
"label.template": "Template",
|
||||||
|
"label.template.select": "Select a template",
|
||||||
"label.templatetag": "Tag",
|
"label.templatetag": "Tag",
|
||||||
"label.template.select.existing": "Select an existing template",
|
"label.template.select.existing": "Select an existing template",
|
||||||
"label.template.temporary.import": "Use a temporary template for import",
|
"label.template.temporary.import": "Use a temporary template for import",
|
||||||
@ -2698,6 +2707,7 @@
|
|||||||
"message.action.delete.ingress.rule": "Please confirm that you want to delete this ingress rule.",
|
"message.action.delete.ingress.rule": "Please confirm that you want to delete this ingress rule.",
|
||||||
"message.action.delete.ipv4.subnet": "Please confirm that you want to delete this IPv4 subnet.",
|
"message.action.delete.ipv4.subnet": "Please confirm that you want to delete this IPv4 subnet.",
|
||||||
"message.action.delete.guest.os": "Please confirm that you want to delete this guest os. System defined entry cannot be deleted.",
|
"message.action.delete.guest.os": "Please confirm that you want to delete this guest os. System defined entry cannot be deleted.",
|
||||||
|
"message.action.delete.guest.os.category": "Please confirm that you want to delete this guest os category.",
|
||||||
"message.action.delete.guest.os.hypervisor.mapping": "Please confirm that you want to delete this guest os hypervisor mapping. System defined entry cannot be deleted.",
|
"message.action.delete.guest.os.hypervisor.mapping": "Please confirm that you want to delete this guest os hypervisor mapping. System defined entry cannot be deleted.",
|
||||||
"message.action.delete.instance.group": "Please confirm that you want to delete the Instance group.",
|
"message.action.delete.instance.group": "Please confirm that you want to delete the Instance group.",
|
||||||
"message.action.delete.interface.static.route": "Please confirm that you want to remove this interface Static Route?",
|
"message.action.delete.interface.static.route": "Please confirm that you want to remove this interface Static Route?",
|
||||||
@ -3306,6 +3316,7 @@
|
|||||||
"message.installwizard.tooltip.tungsten.provider.name": "Tungsten provider name is required",
|
"message.installwizard.tooltip.tungsten.provider.name": "Tungsten provider name is required",
|
||||||
"message.installwizard.tooltip.tungsten.provider.port": "Tungsten provider port is required",
|
"message.installwizard.tooltip.tungsten.provider.port": "Tungsten provider port is required",
|
||||||
"message.installwizard.tooltip.tungsten.provider.vrouterport": "Tungsten provider vrouter port is required",
|
"message.installwizard.tooltip.tungsten.provider.vrouterport": "Tungsten provider vrouter port is required",
|
||||||
|
"message.instance.architecture": "Please select Instance architecture",
|
||||||
"message.instances.managed": "Instances controlled by CloudStack.",
|
"message.instances.managed": "Instances controlled by CloudStack.",
|
||||||
"message.instances.unmanaged": "Instances not controlled by CloudStack.",
|
"message.instances.unmanaged": "Instances not controlled by CloudStack.",
|
||||||
"message.instances.migrate.vmware": "Instances that can be migrated from VMware.",
|
"message.instances.migrate.vmware": "Instances that can be migrated from VMware.",
|
||||||
|
|||||||
@ -139,6 +139,10 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchResourceIcon (id) {
|
fetchResourceIcon (id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
if (this.$store.getters.avatar) {
|
||||||
|
this.image = this.$store.getters.avatar
|
||||||
|
resolve(this.image)
|
||||||
|
}
|
||||||
api('listUsers', {
|
api('listUsers', {
|
||||||
id: id,
|
id: id,
|
||||||
showicon: true
|
showicon: true
|
||||||
@ -146,6 +150,7 @@ export default {
|
|||||||
const response = json.listusersresponse.user || []
|
const response = json.listusersresponse.user || []
|
||||||
if (response?.[0]) {
|
if (response?.[0]) {
|
||||||
this.image = response[0]?.icon?.base64image || ''
|
this.image = response[0]?.icon?.base64image || ''
|
||||||
|
this.$store.commit('SET_AVATAR', this.image)
|
||||||
resolve(this.image)
|
resolve(this.image)
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
|||||||
150
ui/src/components/view/ImageDeployInstanceButton.vue
Normal file
150
ui/src/components/view/ImageDeployInstanceButton.vue
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<a-dropdown-button
|
||||||
|
type="primary"
|
||||||
|
:loading="loading"
|
||||||
|
v-if="allowed"
|
||||||
|
:disabled="!zones || zones.length === 0">
|
||||||
|
<rocket-outlined />
|
||||||
|
{{ $t('label.create.vm') }}
|
||||||
|
<template #icon><down-outlined /></template>
|
||||||
|
<template #overlay>
|
||||||
|
<a-menu type="primary" @click="handleDeployInstanceMenu">
|
||||||
|
<a-menu-item v-for="zone in zones" :key="zone.id">
|
||||||
|
<span v-if="zone.icon && zone.icon.base64image">
|
||||||
|
<resource-icon :image="zone.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||||
|
</span>
|
||||||
|
<global-outlined v-else style="margin-right: 5px" />
|
||||||
|
{{ zone.name }}
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</template>
|
||||||
|
</a-dropdown-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { api } from '@/api'
|
||||||
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ImageDeployInstanceButton',
|
||||||
|
components: {
|
||||||
|
ResourceIcon
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
resource: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
osCategoryId: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update-zones'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
imageApi: 'listTemplates',
|
||||||
|
loading: false,
|
||||||
|
zones: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if (this.$route.meta.name === 'iso') {
|
||||||
|
this.imageApi = 'listIsos'
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
this.fetchData()
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
allowed () {
|
||||||
|
return (this.$route.meta.name === 'template' ||
|
||||||
|
(this.$route.meta.name === 'iso' && this.resource.bootable))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
arrayHasItems (array) {
|
||||||
|
return array !== null && array !== undefined && Array.isArray(array) && array.length > 0
|
||||||
|
},
|
||||||
|
fetchData () {
|
||||||
|
this.fetchResourceData()
|
||||||
|
},
|
||||||
|
fetchResourceData () {
|
||||||
|
const params = {}
|
||||||
|
params.id = this.resource.id
|
||||||
|
params.templatefilter = 'executable'
|
||||||
|
params.listall = true
|
||||||
|
params.page = this.page
|
||||||
|
params.pagesize = this.pageSize
|
||||||
|
|
||||||
|
this.dataSource = []
|
||||||
|
this.itemCount = 0
|
||||||
|
this.fetchLoading = true
|
||||||
|
this.zones = []
|
||||||
|
api(this.imageApi, params).then(json => {
|
||||||
|
const imageResponse = json?.[this.imageApi.toLowerCase() + 'response']?.[this.$route.meta.name] || []
|
||||||
|
this.zones = imageResponse.map(i => ({
|
||||||
|
id: i.zoneid,
|
||||||
|
name: i.zonename
|
||||||
|
}))
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notifyError(error)
|
||||||
|
this.loading = false
|
||||||
|
}).finally(() => {
|
||||||
|
if (this.zones.length !== 0) {
|
||||||
|
this.$emit('update-zones', this.zones)
|
||||||
|
}
|
||||||
|
this.fetchZonesForIcon()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchZonesForIcon () {
|
||||||
|
if (!this.zones) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const zoneids = this.zones.map(z => z.id)
|
||||||
|
this.loading = true
|
||||||
|
api('listZones', { showicon: true, ids: zoneids.join(',') }).then(json => {
|
||||||
|
this.zones = json.listzonesresponse.zone || []
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
if (this.zones.length !== 0) {
|
||||||
|
this.$emit('update-zones', this.zones)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDeployInstanceMenu (e) {
|
||||||
|
const query = { zoneid: e.key }
|
||||||
|
query[this.$route.meta.name + 'id'] = this.resource.id
|
||||||
|
if (this.resource.arch) {
|
||||||
|
query.arch = this.resource.arch
|
||||||
|
}
|
||||||
|
if (this.osCategoryId) {
|
||||||
|
query.oscategoryid = this.osCategoryId
|
||||||
|
}
|
||||||
|
this.$router.push({
|
||||||
|
path: '/action/deployVirtualMachine',
|
||||||
|
query: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -30,11 +30,11 @@
|
|||||||
<edit-outlined class="upload-icon"/>
|
<edit-outlined class="upload-icon"/>
|
||||||
</div>
|
</div>
|
||||||
<slot name="avatar">
|
<slot name="avatar">
|
||||||
<span v-if="(resource.icon && resource.icon.base64image || images.template || images.iso || resourceIcon) && !['router', 'systemvm', 'volume'].includes($route.path.split('/')[1])">
|
<span v-if="resourceIcon && !['router', 'systemvm', 'volume'].includes($route.path.split('/')[1])">
|
||||||
<resource-icon :image="getImage(resource.icon && resource.icon.base64image || images.template || images.iso || resourceIcon)" size="4x" style="margin-right: 5px"/>
|
<resource-icon :image="resourceIcon" size="4x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<os-logo v-if="resource.ostypeid || resource.ostypename" :osId="resource.ostypeid" :osName="resource.ostypename" size="3x" @update-osname="setResourceOsType"/>
|
<os-logo v-if="resource.ostypeid || resource.ostypename || ['guestoscategory'].includes($route.path.split('/')[1])" :osId="resource.ostypeid" :osName="resource.ostypename || resource.name" size="3x" @update-osname="setResourceOsType"/>
|
||||||
<render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 36px" :icon="$route.meta.icon" />
|
<render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 36px" :icon="$route.meta.icon" />
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
v-else-if="$route.meta.icon && Array.isArray($route.meta.icon)"
|
v-else-if="$route.meta.icon && Array.isArray($route.meta.icon)"
|
||||||
@ -158,11 +158,16 @@
|
|||||||
<div class="resource-detail-item" v-if="resource.ostypename && resource.ostypeid">
|
<div class="resource-detail-item" v-if="resource.ostypename && resource.ostypeid">
|
||||||
<div class="resource-detail-item__label">{{ $t('label.ostypename') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.ostypename') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<span v-if="resource.icon && resource.icon.base64image || images.template || images.iso">
|
<span v-if="images.guestoscategory">
|
||||||
<resource-icon :image="getImage(images.template || images.iso)" size="1x" style="margin-right: 5px"/>
|
<resource-icon :image="images.guestoscategory" size="1x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<os-logo v-else :osId="resource.ostypeid" :osName="resource.ostypename" size="lg" style="margin-left: -1px" />
|
<os-logo v-else :osId="resource.ostypeid" :osName="resource.ostypename" size="lg" style="margin-left: -1px" />
|
||||||
<span style="margin-left: 8px">{{ resource.ostypename }}</span>
|
<span style="margin-left: 8px">
|
||||||
|
<router-link v-if="$router.resolve('/guestos/' + resource.ostypeid).matched[0].redirect !== '/exception/404'" :to="{ path: '/guestos/' + resource.ostypeid }">
|
||||||
|
{{ resource.ostypename }}
|
||||||
|
</router-link>
|
||||||
|
<span v-else>{{ resource.ostypename }}</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="resource-detail-item" v-if="resource.ipaddress">
|
<div class="resource-detail-item" v-if="resource.ipaddress">
|
||||||
@ -449,7 +454,7 @@
|
|||||||
<div class="resource-detail-item__label">{{ $t('label.project') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.project') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<span v-if="images.project">
|
<span v-if="images.project">
|
||||||
<resource-icon :image="getImage(images.project)" size="1x" style="margin-right: 5px"/>
|
<resource-icon :image="images.project" size="1x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<project-outlined v-else />
|
<project-outlined v-else />
|
||||||
<router-link v-if="!isStatic && resource.projectid" :to="{ path: '/project/' + resource.projectid }">{{ resource.project || resource.projectname || resource.projectid }}</router-link>
|
<router-link v-if="!isStatic && resource.projectid" :to="{ path: '/project/' + resource.projectid }">{{ resource.project || resource.projectname || resource.projectid }}</router-link>
|
||||||
@ -546,7 +551,7 @@
|
|||||||
<div class="resource-detail-item__label">{{ $t('label.vpcname') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.vpcname') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<span v-if="images.vpc">
|
<span v-if="images.vpc">
|
||||||
<resource-icon :image="getImage(images.vpc)" size="1x" style="margin-right: 5px"/>
|
<resource-icon :image="images.vpc" size="1x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<deployment-unit-outlined v-else />
|
<deployment-unit-outlined v-else />
|
||||||
<router-link :to="{ path: '/vpc/' + resource.vpcid }">{{ resource.vpcname || resource.vpcid }}</router-link>
|
<router-link :to="{ path: '/vpc/' + resource.vpcid }">{{ resource.vpcname || resource.vpcid }}</router-link>
|
||||||
@ -557,7 +562,7 @@
|
|||||||
<div class="resource-detail-item__label">{{ $t('label.aclid') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.aclid') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<span v-if="images.acl">
|
<span v-if="images.acl">
|
||||||
<resource-icon :image="getImage(images.acl)" size="1x" style="margin-right: 5px"/>
|
<resource-icon :image="images.acl" size="1x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<deployment-unit-outlined v-else />
|
<deployment-unit-outlined v-else />
|
||||||
<router-link :to="{ path: '/acllist/' + resource.aclid }">{{ resource.aclname || resource.aclid }}</router-link>
|
<router-link :to="{ path: '/acllist/' + resource.aclid }">{{ resource.aclname || resource.aclid }}</router-link>
|
||||||
@ -578,7 +583,7 @@
|
|||||||
<div class="resource-detail-item" v-if="resource.templateid">
|
<div class="resource-detail-item" v-if="resource.templateid">
|
||||||
<div class="resource-detail-item__label">{{ resource.templateformat === 'ISO'? $t('label.iso') : $t('label.templatename') }}</div>
|
<div class="resource-detail-item__label">{{ resource.templateformat === 'ISO'? $t('label.iso') : $t('label.templatename') }}</div>
|
||||||
<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="images.template || images.guestoscategory" :image="images.template || images.guestoscategory" size="1x" style="margin-right: 5px"/>
|
||||||
<SaveOutlined v-else />
|
<SaveOutlined v-else />
|
||||||
<router-link :to="{ path: (resource.templateformat === 'ISO' ? '/iso/' : '/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>
|
||||||
@ -586,7 +591,7 @@
|
|||||||
<div class="resource-detail-item" v-if="resource.isoid">
|
<div class="resource-detail-item" v-if="resource.isoid">
|
||||||
<div class="resource-detail-item__label">{{ $t('label.isoname') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.isoname') }}</div>
|
||||||
<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="images.iso || (resource.isoid === resource.templateid && images.guestoscategory)" :image="images.iso || images.guestoscategory" size="1x" style="margin-right: 5px"/>
|
||||||
<UsbOutlined v-else />
|
<UsbOutlined v-else />
|
||||||
<router-link :to="{ path: '/iso/' + resource.isoid }">{{ resource.isodisplaytext || resource.isoname || resource.isoid }} </router-link>
|
<router-link :to="{ path: '/iso/' + resource.isoid }">{{ resource.isodisplaytext || resource.isoname || resource.isoid }} </router-link>
|
||||||
</div>
|
</div>
|
||||||
@ -677,7 +682,7 @@
|
|||||||
<div class="resource-detail-item__label">{{ $t('label.zone') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.zone') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<span v-if="images.zone">
|
<span v-if="images.zone">
|
||||||
<resource-icon :image="getImage(images.zone)" size="1x" style="margin-right: 5px"/>
|
<resource-icon :image="images.zone" size="1x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<global-outlined v-else />
|
<global-outlined v-else />
|
||||||
<router-link v-if="!isStatic && $router.resolve('/zone/' + resource.zoneid).matched[0].redirect !== '/exception/404'" :to="{ path: '/zone/' + resource.zoneid }">{{ resource.zone || resource.zonename || resource.zoneid }}</router-link>
|
<router-link v-if="!isStatic && $router.resolve('/zone/' + resource.zoneid).matched[0].redirect !== '/exception/404'" :to="{ path: '/zone/' + resource.zoneid }">{{ resource.zone || resource.zonename || resource.zoneid }}</router-link>
|
||||||
@ -712,7 +717,7 @@
|
|||||||
<div class="resource-detail-item__label">{{ $t('label.account') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.account') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<span v-if="images.account">
|
<span v-if="images.account">
|
||||||
<resource-icon :image="getImage(images.account)" size="1x" style="margin-right: 5px"/>
|
<resource-icon :image="images.account" size="1x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<user-outlined v-else />
|
<user-outlined v-else />
|
||||||
<router-link v-if="!isStatic && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/account', query: { name: resource.account, domainid: resource.domainid } }">{{ resource.account }}</router-link>
|
<router-link v-if="!isStatic && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/account', query: { name: resource.account, domainid: resource.domainid } }">{{ resource.account }}</router-link>
|
||||||
@ -730,7 +735,7 @@
|
|||||||
<div class="resource-detail-item" v-if="resource.domainid">
|
<div class="resource-detail-item" v-if="resource.domainid">
|
||||||
<div class="resource-detail-item__label">{{ $t('label.domain') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.domain') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<resource-icon v-if="images.domain" :image="getImage(images.domain)" size="1x" style="margin-right: 5px"/>
|
<resource-icon v-if="images.domain" :image="images.domain" size="1x" style="margin-right: 5px"/>
|
||||||
<block-outlined v-else />
|
<block-outlined v-else />
|
||||||
<router-link v-if="!isStatic && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/domain/' + resource.domainid, query: { tab: 'details'} }">{{ resource.domain || resource.domainid }}</router-link>
|
<router-link v-if="!isStatic && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/domain/' + resource.domainid, query: { tab: 'details'} }">{{ resource.domain || resource.domainid }}</router-link>
|
||||||
<span v-else>{{ resource.domain || resource.domainid }}</span>
|
<span v-else>{{ resource.domain || resource.domainid }}</span>
|
||||||
@ -788,6 +793,10 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
<image-deploy-instance-button
|
||||||
|
v-if="'deployVirtualMachine' in $store.getters.apis && ['template', 'iso'].includes($route.meta.name)"
|
||||||
|
:resource="resource"
|
||||||
|
:osCategoryId="osCategoryId" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="account-center-tags" v-if="showKeys || resource.apikeyaccess">
|
<div class="account-center-tags" v-if="showKeys || resource.apikeyaccess">
|
||||||
@ -894,6 +903,7 @@ import UploadResourceIcon from '@/components/view/UploadResourceIcon'
|
|||||||
import eventBus from '@/config/eventBus'
|
import eventBus from '@/config/eventBus'
|
||||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
import ResourceLabel from '@/components/widgets/ResourceLabel'
|
import ResourceLabel from '@/components/widgets/ResourceLabel'
|
||||||
|
import ImageDeployInstanceButton from '@/components/view/ImageDeployInstanceButton.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'InfoCard',
|
name: 'InfoCard',
|
||||||
@ -905,7 +915,8 @@ export default {
|
|||||||
TooltipButton,
|
TooltipButton,
|
||||||
UploadResourceIcon,
|
UploadResourceIcon,
|
||||||
ResourceIcon,
|
ResourceIcon,
|
||||||
ResourceLabel
|
ResourceLabel,
|
||||||
|
ImageDeployInstanceButton
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
resource: {
|
resource: {
|
||||||
@ -951,7 +962,8 @@ export default {
|
|||||||
network: ''
|
network: ''
|
||||||
},
|
},
|
||||||
newResource: {},
|
newResource: {},
|
||||||
validLinks: {}
|
validLinks: {},
|
||||||
|
osCategoryId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -975,9 +987,6 @@ export default {
|
|||||||
}
|
}
|
||||||
this.updateResourceAdditionalData()
|
this.updateResourceAdditionalData()
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async templateIcon () {
|
|
||||||
this.getIcons()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
@ -1007,22 +1016,31 @@ export default {
|
|||||||
}
|
}
|
||||||
return [this.resource.keypairs.toString()]
|
return [this.resource.keypairs.toString()]
|
||||||
},
|
},
|
||||||
templateIcon () {
|
isResourceShowingParentResourceIcon () {
|
||||||
return this.resource.templateid
|
const resourcesShowParentResourceIcon = ['guestos']
|
||||||
|
const routeName = this.$route.path.split('/')?.[1] || null
|
||||||
|
if (!routeName) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return resourcesShowParentResourceIcon.includes(routeName)
|
||||||
},
|
},
|
||||||
resourceIcon () {
|
resourceIcon () {
|
||||||
if (this.$showIcon()) {
|
if (!this.$showIcon() && !this.isResourceShowingParentResourceIcon) {
|
||||||
if (this.resource?.icon?.base64image) {
|
return null
|
||||||
return this.resource.icon.base64image
|
|
||||||
}
|
|
||||||
if (this.resource?.resourceIcon?.base64image) {
|
|
||||||
return this.resource.resourceIcon.base64image
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null
|
if (this.resource?.icon?.base64image) {
|
||||||
|
return this.resource.icon.base64image
|
||||||
|
}
|
||||||
|
if (this.resource?.resourceIcon?.base64image) {
|
||||||
|
return this.resource.resourceIcon.base64image
|
||||||
|
}
|
||||||
|
return this.images.template || this.images.iso || this.images.guestoscategory || null
|
||||||
},
|
},
|
||||||
routeFromResourceType () {
|
routeFromResourceType () {
|
||||||
return this.$getRouteFromResourceType(this.resource.resourcetype)
|
return this.$getRouteFromResourceType(this.resource.resourcetype)
|
||||||
|
},
|
||||||
|
isModernImageSelection () {
|
||||||
|
return this.$config.imageSelectionInterface === undefined || this.$config.imageSelectionInterface === 'modern'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -1037,6 +1055,15 @@ export default {
|
|||||||
this.getTags()
|
this.getTags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const osId = this.resource.guestosid || this.resource.ostypeid
|
||||||
|
if (osId && 'listOsTypes' in this.$store.getters.apis) {
|
||||||
|
api('listOsTypes', { id: osId }).then(json => {
|
||||||
|
this.osCategoryId = json?.listostypesresponse?.ostype?.[0]?.oscategoryid || null
|
||||||
|
if (this.osCategoryId) {
|
||||||
|
this.fetchResourceIcon(this.osCategoryId, 'guestoscategory')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
this.getIcons()
|
this.getIcons()
|
||||||
},
|
},
|
||||||
showUploadModal (show) {
|
showUploadModal (show) {
|
||||||
@ -1048,43 +1075,34 @@ export default {
|
|||||||
this.showUpload = false
|
this.showUpload = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getImage (image) {
|
getIcons () {
|
||||||
return (image || this.resource?.icon?.base64image)
|
this.images = {}
|
||||||
},
|
|
||||||
async getIcons () {
|
|
||||||
this.images = {
|
|
||||||
zone: '',
|
|
||||||
template: '',
|
|
||||||
iso: '',
|
|
||||||
domain: '',
|
|
||||||
account: '',
|
|
||||||
project: '',
|
|
||||||
vpc: '',
|
|
||||||
network: ''
|
|
||||||
}
|
|
||||||
if (this.resource.templateid) {
|
if (this.resource.templateid) {
|
||||||
await this.fetchResourceIcon(this.resource.templateid, 'template')
|
this.fetchResourceIcon(this.resource.templateid, 'template')
|
||||||
}
|
}
|
||||||
if (this.resource.isoid) {
|
if (this.resource.isoid) {
|
||||||
await this.fetchResourceIcon(this.resource.isoid, 'iso')
|
this.fetchResourceIcon(this.resource.isoid, 'iso')
|
||||||
}
|
}
|
||||||
if (this.resource.zoneid) {
|
if (this.resource.zoneid) {
|
||||||
await this.fetchResourceIcon(this.resource.zoneid, 'zone')
|
this.fetchResourceIcon(this.resource.zoneid, 'zone')
|
||||||
}
|
}
|
||||||
if (this.resource.domainid) {
|
if (this.resource.domainid) {
|
||||||
await this.fetchResourceIcon(this.resource.domainid, 'domain')
|
this.fetchResourceIcon(this.resource.domainid, 'domain')
|
||||||
}
|
}
|
||||||
if (this.resource.account) {
|
if (this.resource.account) {
|
||||||
await this.fetchAccount()
|
this.fetchAccount()
|
||||||
}
|
}
|
||||||
if (this.resource.projectid) {
|
if (this.resource.projectid) {
|
||||||
await this.fetchResourceIcon(this.resource.projectid, 'project')
|
this.fetchResourceIcon(this.resource.projectid, 'project')
|
||||||
}
|
}
|
||||||
if (this.resource.vpcid) {
|
if (this.resource.vpcid) {
|
||||||
await this.fetchResourceIcon(this.resource.vpcid, 'vpc')
|
this.fetchResourceIcon(this.resource.vpcid, 'vpc')
|
||||||
}
|
}
|
||||||
if (this.resource.networkid) {
|
if (this.resource.networkid) {
|
||||||
await this.fetchResourceIcon(this.resource.networkid, 'network')
|
this.fetchResourceIcon(this.resource.networkid, 'network')
|
||||||
|
}
|
||||||
|
if (this.resource.oscategoryid) {
|
||||||
|
this.fetchResourceIcon(this.resource.oscategoryid, 'guestoscategory')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetchAccount () {
|
fetchAccount () {
|
||||||
@ -1109,19 +1127,14 @@ export default {
|
|||||||
resourcetype: type
|
resourcetype: type
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
const response = json.listresourceiconresponse.icon || []
|
const response = json.listresourceiconresponse.icon || []
|
||||||
if (response?.[0]) {
|
this.images[type] = response?.[0]?.base64image || null
|
||||||
this.images[type] = response[0].base64image
|
resolve(this.images)
|
||||||
resolve(this.images)
|
|
||||||
} else {
|
|
||||||
this.images[type] = ''
|
|
||||||
resolve(this.images)
|
|
||||||
}
|
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
reject(error)
|
reject(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.images.type = ''
|
this.images.type = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setData () {
|
setData () {
|
||||||
@ -1252,7 +1265,6 @@ export default {
|
|||||||
query[item.param] = this.resource.id
|
query[item.param] = this.resource.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<span v-if="$showIcon() && !['vm', 'vnfapp'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
<span v-if="$showIcon() && !['vm', 'vnfapp'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
||||||
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="2x"/>
|
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="2x"/>
|
||||||
<os-logo v-else-if="record.ostypename" :osName="record.ostypename" size="xl" />
|
<os-logo v-else-if="record.ostypename || ['guestoscategory'].includes($route.path.split('/')[1])" :osName="record.ostypename || record.name" size="xl" />
|
||||||
<render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 16px;" :icon="$route.meta.icon"/>
|
<render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 16px;" :icon="$route.meta.icon"/>
|
||||||
<render-icon v-else style="font-size: 16px;" :svgIcon="$route.meta.icon" />
|
<render-icon v-else style="font-size: 16px;" :svgIcon="$route.meta.icon" />
|
||||||
</span>
|
</span>
|
||||||
@ -241,6 +241,15 @@
|
|||||||
</span>
|
</span>
|
||||||
<span v-else>{{ text }}</span>
|
<span v-else>{{ text }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="column.key === 'oscategoryname'">
|
||||||
|
<span v-if="('listOsCategories' in $store.getters.apis) && record.oscategoryid">
|
||||||
|
<router-link :to="{ path: '/guestoscategory/' + record.oscategoryid }">{{ text }}</router-link>
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ text }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'isuserdefined'">
|
||||||
|
<span>{{ text ? $t('label.yes') : $t('label.no') }}</span>
|
||||||
|
</template>
|
||||||
<template v-if="column.key === 'state'">
|
<template v-if="column.key === 'state'">
|
||||||
<status v-if="$route.path.startsWith('/host')" :text="getHostState(record)" displayText />
|
<status v-if="$route.path.startsWith('/host')" :text="getHostState(record)" displayText />
|
||||||
<status v-else :text="text ? text : ''" displayText :styles="{ 'min-width': '80px' }" />
|
<status v-else :text="text ? text : ''" displayText :styles="{ 'min-width': '80px' }" />
|
||||||
@ -485,6 +494,9 @@
|
|||||||
<template v-if="['startdate', 'enddate'].includes(column.key) && ['usage'].includes($route.path.split('/')[1])">
|
<template v-if="['startdate', 'enddate'].includes(column.key) && ['usage'].includes($route.path.split('/')[1])">
|
||||||
{{ $toLocaleDate(text.replace('\'T\'', ' ')) }}
|
{{ $toLocaleDate(text.replace('\'T\'', ' ')) }}
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="['isfeatured'].includes(column.key) && ['guestoscategory'].includes($route.path.split('/')[1])">
|
||||||
|
{{ record.isfeatured ? $t('label.yes') : $t('label.no') }}
|
||||||
|
</template>
|
||||||
<template v-if="column.key === 'order'">
|
<template v-if="column.key === 'order'">
|
||||||
<div class="shift-btns">
|
<div class="shift-btns">
|
||||||
<a-tooltip :name="text" placement="top">
|
<a-tooltip :name="text" placement="top">
|
||||||
@ -756,7 +768,7 @@ export default {
|
|||||||
'vmsnapshot', 'backup', 'guestnetwork', 'vpc', 'publicip', 'vpnuser', 'vpncustomergateway', 'vnfapp',
|
'vmsnapshot', 'backup', 'guestnetwork', 'vpc', 'publicip', 'vpnuser', 'vpncustomergateway', 'vnfapp',
|
||||||
'project', 'account', 'systemvm', 'router', 'computeoffering', 'systemoffering',
|
'project', 'account', 'systemvm', 'router', 'computeoffering', 'systemoffering',
|
||||||
'diskoffering', 'backupoffering', 'networkoffering', 'vpcoffering', 'ilbvm', 'kubernetes', 'comment', 'buckets',
|
'diskoffering', 'backupoffering', 'networkoffering', 'vpcoffering', 'ilbvm', 'kubernetes', 'comment', 'buckets',
|
||||||
'webhook', 'webhookdeliveries', 'sharedfs', 'ipv4subnets', 'asnumbers'
|
'webhook', 'webhookdeliveries', 'sharedfs', 'ipv4subnets', 'asnumbers', 'guestos'
|
||||||
].includes(this.$route.name)
|
].includes(this.$route.name)
|
||||||
},
|
},
|
||||||
getDateAtTimeZone (date, timezone) {
|
getDateAtTimeZone (date, timezone) {
|
||||||
@ -859,8 +871,9 @@ export default {
|
|||||||
case 'vpcoffering':
|
case 'vpcoffering':
|
||||||
apiString = 'updateVPCOffering'
|
apiString = 'updateVPCOffering'
|
||||||
break
|
break
|
||||||
default:
|
case 'guestoscategory':
|
||||||
apiString = 'updateTemplate'
|
apiString = 'updateOsCategory'
|
||||||
|
break
|
||||||
}
|
}
|
||||||
return apiString
|
return apiString
|
||||||
},
|
},
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<img :src="getImg()" :height="getDimensions()" :width="getDimensions()" :style="{ marginTop: (getDimensions() === 56 || ['deployVirtualMachine'].includes($route.path.split('/')[2])) ? '' : '-5px' }"/>
|
<img :src="computedImage" :height="dimensions" :width="dimensions" :style="{ marginTop: (dimensions === 56 || ['deployVirtualMachine'].includes($route.path.split('/')[2])) ? '' : '-5px' }"/>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
@ -34,15 +34,17 @@ export default {
|
|||||||
data () {
|
data () {
|
||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
methods: {
|
computed: {
|
||||||
getImg () {
|
computedImage () {
|
||||||
|
if (!this.image) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
if (this.image.startsWith('data:image/png')) {
|
if (this.image.startsWith('data:image/png')) {
|
||||||
return this.image
|
return this.image
|
||||||
} else {
|
|
||||||
return 'data:image/png;charset=utf-8;base64, ' + this.image
|
|
||||||
}
|
}
|
||||||
|
return 'data:image/png;charset=utf-8;base64, ' + this.image
|
||||||
},
|
},
|
||||||
getDimensions () {
|
dimensions () {
|
||||||
const num = Number(this.size)
|
const num = Number(this.size)
|
||||||
if (Number.isInteger(num) && num > 0) {
|
if (Number.isInteger(num) && num > 0) {
|
||||||
return num
|
return num
|
||||||
@ -54,6 +56,8 @@ export default {
|
|||||||
return 24
|
return 24
|
||||||
case '1x':
|
case '1x':
|
||||||
return 16
|
return 16
|
||||||
|
case 'os':
|
||||||
|
return 28
|
||||||
default:
|
default:
|
||||||
return 16
|
return 16
|
||||||
}
|
}
|
||||||
|
|||||||
@ -309,7 +309,7 @@ export default {
|
|||||||
'clusterid', 'podid', 'groupid', 'entitytype', 'accounttype', 'systemvmtype', 'scope', 'provider',
|
'clusterid', 'podid', 'groupid', 'entitytype', 'accounttype', 'systemvmtype', 'scope', 'provider',
|
||||||
'type', 'scope', 'managementserverid', 'serviceofferingid',
|
'type', 'scope', 'managementserverid', 'serviceofferingid',
|
||||||
'diskofferingid', 'networkid', 'usagetype', 'restartrequired',
|
'diskofferingid', 'networkid', 'usagetype', 'restartrequired',
|
||||||
'displaynetwork', 'guestiptype', 'usersource', 'arch'].includes(item)
|
'displaynetwork', 'guestiptype', 'usersource', 'arch', 'oscategoryid', 'templatetype'].includes(item)
|
||||||
) {
|
) {
|
||||||
type = 'list'
|
type = 'list'
|
||||||
} else if (item === 'tags') {
|
} else if (item === 'tags') {
|
||||||
@ -458,6 +458,13 @@ export default {
|
|||||||
this.fields[typeIndex].opts = this.$fetchCpuArchitectureTypes()
|
this.fields[typeIndex].opts = this.$fetchCpuArchitectureTypes()
|
||||||
this.fields[typeIndex].loading = false
|
this.fields[typeIndex].loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arrayField.includes('templatetype')) {
|
||||||
|
const typeIndex = this.fields.findIndex(item => item.name === 'templatetype')
|
||||||
|
this.fields[typeIndex].loading = true
|
||||||
|
this.fields[typeIndex].opts = this.$fetchTemplateTypes()
|
||||||
|
this.fields[typeIndex].loading = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async fetchDynamicFieldData (arrayField, searchKeyword) {
|
async fetchDynamicFieldData (arrayField, searchKeyword) {
|
||||||
const promises = []
|
const promises = []
|
||||||
@ -477,6 +484,7 @@ export default {
|
|||||||
let networkIndex = -1
|
let networkIndex = -1
|
||||||
let usageTypeIndex = -1
|
let usageTypeIndex = -1
|
||||||
let volumeIndex = -1
|
let volumeIndex = -1
|
||||||
|
let osCategoryIndex = -1
|
||||||
|
|
||||||
if (arrayField.includes('type')) {
|
if (arrayField.includes('type')) {
|
||||||
if (this.$route.path === '/alert') {
|
if (this.$route.path === '/alert') {
|
||||||
@ -580,6 +588,12 @@ export default {
|
|||||||
promises.push(await this.fetchVolumes(searchKeyword))
|
promises.push(await this.fetchVolumes(searchKeyword))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arrayField.includes('oscategoryid')) {
|
||||||
|
osCategoryIndex = this.fields.findIndex(item => item.name === 'oscategoryid')
|
||||||
|
this.fields[osCategoryIndex].loading = true
|
||||||
|
promises.push(await this.fetchOsCategories(searchKeyword))
|
||||||
|
}
|
||||||
|
|
||||||
Promise.all(promises).then(response => {
|
Promise.all(promises).then(response => {
|
||||||
if (typeIndex > -1) {
|
if (typeIndex > -1) {
|
||||||
const types = response.filter(item => item.type === 'type')
|
const types = response.filter(item => item.type === 'type')
|
||||||
@ -676,6 +690,13 @@ export default {
|
|||||||
this.fields[usageTypeIndex].opts = this.sortArray(usageTypes[0].data)
|
this.fields[usageTypeIndex].opts = this.sortArray(usageTypes[0].data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (osCategoryIndex > -1) {
|
||||||
|
const osCategories = response.filter(item => item.type === 'oscategoryid')
|
||||||
|
if (osCategories && osCategories.length > 0) {
|
||||||
|
this.fields[osCategoryIndex].opts = this.sortArray(osCategories[0].data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
if (typeIndex > -1) {
|
if (typeIndex > -1) {
|
||||||
this.fields[typeIndex].loading = false
|
this.fields[typeIndex].loading = false
|
||||||
@ -722,6 +743,9 @@ export default {
|
|||||||
if (usageTypeIndex > -1) {
|
if (usageTypeIndex > -1) {
|
||||||
this.fields[usageTypeIndex].loading = false
|
this.fields[usageTypeIndex].loading = false
|
||||||
}
|
}
|
||||||
|
if (osCategoryIndex > -1) {
|
||||||
|
this.fields[osCategoryIndex].loading = false
|
||||||
|
}
|
||||||
if (Array.isArray(arrayField)) {
|
if (Array.isArray(arrayField)) {
|
||||||
this.fillFormFieldValues()
|
this.fillFormFieldValues()
|
||||||
}
|
}
|
||||||
@ -1006,6 +1030,19 @@ export default {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
fetchOsCategories (searchKeyword) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
api('listOsCategories', { showicon: true, keyword: searchKeyword }).then(json => {
|
||||||
|
const osCategories = json.listoscategoriesresponse.oscategory
|
||||||
|
resolve({
|
||||||
|
type: 'oscategoryid',
|
||||||
|
data: osCategories
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error.response.headers['x-description'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
fetchGuestNetworkTypes () {
|
fetchGuestNetworkTypes () {
|
||||||
const types = []
|
const types = []
|
||||||
if (this.apiName.indexOf('listNetworks') > -1) {
|
if (this.apiName.indexOf('listNetworks') > -1) {
|
||||||
|
|||||||
154
ui/src/components/widgets/BlockRadioGroupSelect.vue
Normal file
154
ui/src/components/widgets/BlockRadioGroupSelect.vue
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-radio-group
|
||||||
|
v-if="items.length <= maxBlocks"
|
||||||
|
v-model:value="localValue"
|
||||||
|
@change="handleChange()">
|
||||||
|
<a-row type="flex" :gutter="[horizontalGutter, verticalGutter]" justify="start">
|
||||||
|
<div v-for="item in items" :key="item.id">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-radio-button
|
||||||
|
:value="item.id"
|
||||||
|
style="border-width: 2px"
|
||||||
|
:class="blockRadioButtonClass">
|
||||||
|
<slot name="radio-option" :item="item"></slot>
|
||||||
|
</a-radio-button>
|
||||||
|
</a-col>
|
||||||
|
</div>
|
||||||
|
</a-row>
|
||||||
|
</a-radio-group>
|
||||||
|
<a-select
|
||||||
|
v-else
|
||||||
|
v-model:value="localValue"
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
:filterOption="(input, option) => {
|
||||||
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
}"
|
||||||
|
@change="handleChange()"
|
||||||
|
:loading="loading"
|
||||||
|
v-focus="true">
|
||||||
|
<a-select-option v-for="item in items" :key="item.id" :label="item.name">
|
||||||
|
<slot name="select-option" :item="item"></slot>
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BlockRadioGroupSelect',
|
||||||
|
props: {
|
||||||
|
blockSize: {
|
||||||
|
type: String,
|
||||||
|
default: 'large'
|
||||||
|
},
|
||||||
|
selectedValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
horizontalGutter: {
|
||||||
|
type: Number,
|
||||||
|
default: 16
|
||||||
|
},
|
||||||
|
verticalGutter: {
|
||||||
|
type: Number,
|
||||||
|
default: 18
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
maxBlocks: {
|
||||||
|
type: Number,
|
||||||
|
default: 8
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
localValue: this.selectedValue
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedValue (newValue) {
|
||||||
|
if (this.localValue === newValue) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.localValue = newValue
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
blockRadioButtonClass () {
|
||||||
|
if (['square', 'medium', 'small'].includes(this.blockSize)) {
|
||||||
|
return this.blockSize + '-block-radio-button'
|
||||||
|
}
|
||||||
|
return 'large-block-radio-button'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['change'],
|
||||||
|
methods: {
|
||||||
|
handleChange () {
|
||||||
|
this.$emit('change', this.localValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.large-block-radio-button {
|
||||||
|
width:100%;
|
||||||
|
min-width: 345px;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
padding-left: 20px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.medium-block-radio-button {
|
||||||
|
width:100%;
|
||||||
|
min-width: 160px;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
padding-left: 20px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.small-block-radio-button {
|
||||||
|
width:100%;
|
||||||
|
min-width: 80px;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
padding-left: 20px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.square-block-radio-button {
|
||||||
|
width: 88px;
|
||||||
|
height: 88px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -21,7 +21,7 @@
|
|||||||
{{ name }}
|
{{ name }}
|
||||||
</template>
|
</template>
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
:icon="['fab', logo]"
|
:icon="logo"
|
||||||
:size="size"
|
:size="size"
|
||||||
:style="[$store.getters.darkMode ? { color: 'rgba(255, 255, 255, 0.65)' } : { color: '#666' }]"
|
:style="[$store.getters.darkMode ? { color: 'rgba(255, 255, 255, 0.65)' } : { color: '#666' }]"
|
||||||
/>
|
/>
|
||||||
@ -50,7 +50,7 @@ export default {
|
|||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
name: '',
|
name: '',
|
||||||
osLogo: 'linux'
|
osLogo: ['fas', 'image']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -87,35 +87,34 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
getFontAwesomeIcon (name) {
|
||||||
|
return ['fab', name]
|
||||||
|
},
|
||||||
discoverOsLogo (name) {
|
discoverOsLogo (name) {
|
||||||
this.name = name
|
this.name = name
|
||||||
const osname = name.toLowerCase()
|
|
||||||
if (osname.includes('centos')) {
|
|
||||||
this.osLogo = 'centos'
|
|
||||||
} else if (osname.includes('debian')) {
|
|
||||||
this.osLogo = 'debian'
|
|
||||||
} else if (osname.includes('ubuntu')) {
|
|
||||||
this.osLogo = 'ubuntu'
|
|
||||||
} else if (osname.includes('suse')) {
|
|
||||||
this.osLogo = 'suse'
|
|
||||||
} else if (osname.includes('redhat')) {
|
|
||||||
this.osLogo = 'redhat'
|
|
||||||
} else if (osname.includes('fedora')) {
|
|
||||||
this.osLogo = 'fedora'
|
|
||||||
} else if (osname.includes('linux')) {
|
|
||||||
this.osLogo = 'linux'
|
|
||||||
} else if (osname.includes('bsd')) {
|
|
||||||
this.osLogo = 'freebsd'
|
|
||||||
} else if (osname.includes('apple')) {
|
|
||||||
this.osLogo = 'apple'
|
|
||||||
} else if (osname.includes('window') || osname.includes('dos')) {
|
|
||||||
this.osLogo = 'windows'
|
|
||||||
} else if (osname.includes('oracle')) {
|
|
||||||
this.osLogo = 'java'
|
|
||||||
} else {
|
|
||||||
this.osLogo = 'linux'
|
|
||||||
}
|
|
||||||
this.$emit('update-osname', this.name)
|
this.$emit('update-osname', this.name)
|
||||||
|
const osname = name.toLowerCase()
|
||||||
|
const logos = [
|
||||||
|
{ name: 'centos' },
|
||||||
|
{ name: 'debian' },
|
||||||
|
{ name: 'ubuntu' },
|
||||||
|
{ name: 'suse' },
|
||||||
|
{ name: 'redhat' },
|
||||||
|
{ name: 'fedora' },
|
||||||
|
{ name: 'linux' },
|
||||||
|
{ name: 'bsd', alternate: 'freebsd' },
|
||||||
|
{ name: 'apple' },
|
||||||
|
{ name: 'macos', alternate: 'apple' },
|
||||||
|
{ name: 'window', alternate: 'windows' },
|
||||||
|
{ name: 'dos', alternate: 'windows' },
|
||||||
|
{ name: 'oracle', alternate: 'java' }
|
||||||
|
]
|
||||||
|
const match = logos.find(entry => osname.includes(entry.name))
|
||||||
|
if (match) {
|
||||||
|
this.osLogo = ['fab', match.alternate ? match.alternate : match.name]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.osLogo = ['fas', 'image']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -187,6 +187,56 @@ export default {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'guestoscategory',
|
||||||
|
title: 'label.guest.os.categories',
|
||||||
|
docHelp: 'adminguide/guest_os.html#guest-os-categories',
|
||||||
|
icon: 'group-outlined',
|
||||||
|
permission: ['listOsCategories', 'addOsCategory'],
|
||||||
|
columns: ['name', 'isfeatured', 'created', 'order'],
|
||||||
|
details: ['name', 'isfeatured', 'created'],
|
||||||
|
related: [{
|
||||||
|
name: 'guestos',
|
||||||
|
title: 'label.guest.os',
|
||||||
|
param: 'oscategoryid'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'template',
|
||||||
|
title: 'label.templates',
|
||||||
|
param: 'oscategoryid'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'iso',
|
||||||
|
title: 'label.isos',
|
||||||
|
param: 'oscategoryid'
|
||||||
|
}],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
api: 'addOsCategory',
|
||||||
|
icon: 'plus-outlined',
|
||||||
|
label: 'label.add.guest.os.category',
|
||||||
|
listView: true,
|
||||||
|
dataView: false,
|
||||||
|
args: ['name', 'isfeatured']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'updateOsCategory',
|
||||||
|
icon: 'edit-outlined',
|
||||||
|
label: 'label.edit',
|
||||||
|
dataView: true,
|
||||||
|
popup: true,
|
||||||
|
args: ['name', 'isfeatured']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'deleteOsCategory',
|
||||||
|
icon: 'delete-outlined',
|
||||||
|
label: 'label.action.delete.guest.os.category',
|
||||||
|
message: 'message.action.delete.guest.os.category',
|
||||||
|
dataView: true,
|
||||||
|
popup: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'guestos',
|
name: 'guestos',
|
||||||
title: 'label.guest.os',
|
title: 'label.guest.os',
|
||||||
@ -195,6 +245,7 @@ export default {
|
|||||||
permission: ['listOsTypes', 'listOsCategories'],
|
permission: ['listOsTypes', 'listOsCategories'],
|
||||||
columns: ['name', 'oscategoryname', 'isuserdefined'],
|
columns: ['name', 'oscategoryname', 'isuserdefined'],
|
||||||
details: ['name', 'oscategoryname', 'isuserdefined'],
|
details: ['name', 'oscategoryname', 'isuserdefined'],
|
||||||
|
searchFilters: ['oscategoryid'],
|
||||||
related: [{
|
related: [{
|
||||||
name: 'guestoshypervisormapping',
|
name: 'guestoshypervisormapping',
|
||||||
title: 'label.guest.os.hypervisor.mappings',
|
title: 'label.guest.os.hypervisor.mappings',
|
||||||
@ -221,7 +272,14 @@ export default {
|
|||||||
label: 'label.edit',
|
label: 'label.edit',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
popup: true,
|
popup: true,
|
||||||
args: ['osdisplayname']
|
groupAction: true,
|
||||||
|
groupMap: (selection, values) => { return selection.map(x => { return { id: x, oscategoryid: values.oscategoryid } }) },
|
||||||
|
args: (record, store, isGroupAction) => {
|
||||||
|
if (isGroupAction) {
|
||||||
|
return ['oscategoryid']
|
||||||
|
}
|
||||||
|
return ['osdisplayname', 'oscategoryid']
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
api: 'addGuestOsMapping',
|
api: 'addGuestOsMapping',
|
||||||
|
|||||||
@ -67,7 +67,7 @@ export default {
|
|||||||
return fields
|
return fields
|
||||||
},
|
},
|
||||||
searchFilters: () => {
|
searchFilters: () => {
|
||||||
var filters = ['name', 'zoneid', 'tags', 'arch']
|
var filters = ['name', 'zoneid', 'tags', 'arch', 'oscategoryid', 'templatetype']
|
||||||
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
|
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
|
||||||
filters.push('storageid')
|
filters.push('storageid')
|
||||||
filters.push('imagestoreid')
|
filters.push('imagestoreid')
|
||||||
@ -235,7 +235,7 @@ export default {
|
|||||||
},
|
},
|
||||||
details: ['name', 'id', 'displaytext', 'checksum', 'ostypename', 'size', 'arch', 'bootable', 'isready', 'passwordenabled', 'directdownload', 'isextractable', 'ispublic', 'isfeatured', 'isdynamicallyscalable', 'crosszones', 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url'],
|
details: ['name', 'id', 'displaytext', 'checksum', 'ostypename', 'size', 'arch', 'bootable', 'isready', 'passwordenabled', 'directdownload', 'isextractable', 'ispublic', 'isfeatured', 'isdynamicallyscalable', 'crosszones', 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url'],
|
||||||
searchFilters: () => {
|
searchFilters: () => {
|
||||||
var filters = ['name', 'zoneid', 'tags', 'arch']
|
var filters = ['name', 'zoneid', 'tags', 'arch', 'oscategoryid']
|
||||||
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
|
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
|
||||||
filters.push('storageid')
|
filters.push('storageid')
|
||||||
filters.push('imagestoreid')
|
filters.push('imagestoreid')
|
||||||
|
|||||||
@ -48,6 +48,7 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
TimePicker,
|
TimePicker,
|
||||||
|
Typography,
|
||||||
Upload,
|
Upload,
|
||||||
Progress,
|
Progress,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
@ -117,6 +118,7 @@ export default {
|
|||||||
app.use(Divider)
|
app.use(Divider)
|
||||||
app.use(DatePicker)
|
app.use(DatePicker)
|
||||||
app.use(TimePicker)
|
app.use(TimePicker)
|
||||||
|
app.use(Typography)
|
||||||
app.use(Upload)
|
app.use(Upload)
|
||||||
app.use(Progress)
|
app.use(Progress)
|
||||||
app.use(Skeleton)
|
app.use(Skeleton)
|
||||||
|
|||||||
@ -83,6 +83,7 @@ import {
|
|||||||
FileDoneOutlined,
|
FileDoneOutlined,
|
||||||
FileProtectOutlined,
|
FileProtectOutlined,
|
||||||
FileTextOutlined,
|
FileTextOutlined,
|
||||||
|
FileZipOutlined,
|
||||||
FilterOutlined,
|
FilterOutlined,
|
||||||
FilterTwoTone,
|
FilterTwoTone,
|
||||||
FireOutlined,
|
FireOutlined,
|
||||||
@ -99,6 +100,7 @@ import {
|
|||||||
GlobalOutlined,
|
GlobalOutlined,
|
||||||
GoldOutlined,
|
GoldOutlined,
|
||||||
GoogleOutlined,
|
GoogleOutlined,
|
||||||
|
GroupOutlined,
|
||||||
HddOutlined,
|
HddOutlined,
|
||||||
HomeOutlined,
|
HomeOutlined,
|
||||||
IdcardOutlined,
|
IdcardOutlined,
|
||||||
@ -253,6 +255,7 @@ export default {
|
|||||||
app.component('FileDoneOutlined', FileDoneOutlined)
|
app.component('FileDoneOutlined', FileDoneOutlined)
|
||||||
app.component('FileProtectOutlined', FileProtectOutlined)
|
app.component('FileProtectOutlined', FileProtectOutlined)
|
||||||
app.component('FileTextOutlined', FileTextOutlined)
|
app.component('FileTextOutlined', FileTextOutlined)
|
||||||
|
app.component('FileZipOutlined', FileZipOutlined)
|
||||||
app.component('FilterOutlined', FilterOutlined)
|
app.component('FilterOutlined', FilterOutlined)
|
||||||
app.component('FilterTwoTone', FilterTwoTone)
|
app.component('FilterTwoTone', FilterTwoTone)
|
||||||
app.component('FireOutlined', FireOutlined)
|
app.component('FireOutlined', FireOutlined)
|
||||||
@ -269,6 +272,7 @@ export default {
|
|||||||
app.component('GlobalOutlined', GlobalOutlined)
|
app.component('GlobalOutlined', GlobalOutlined)
|
||||||
app.component('GoldOutlined', GoldOutlined)
|
app.component('GoldOutlined', GoldOutlined)
|
||||||
app.component('GoogleOutlined', GoogleOutlined)
|
app.component('GoogleOutlined', GoogleOutlined)
|
||||||
|
app.component('GroupOutlined', GroupOutlined)
|
||||||
app.component('HddOutlined', HddOutlined)
|
app.component('HddOutlined', HddOutlined)
|
||||||
app.component('HomeOutlined', HomeOutlined)
|
app.component('HomeOutlined', HomeOutlined)
|
||||||
app.component('IdcardOutlined', IdcardOutlined)
|
app.component('IdcardOutlined', IdcardOutlined)
|
||||||
|
|||||||
@ -37,7 +37,8 @@ import {
|
|||||||
genericUtilPlugin,
|
genericUtilPlugin,
|
||||||
localesPlugin,
|
localesPlugin,
|
||||||
dialogUtilPlugin,
|
dialogUtilPlugin,
|
||||||
cpuArchitectureUtilPlugin
|
cpuArchitectureUtilPlugin,
|
||||||
|
imagesUtilPlugin
|
||||||
} from './utils/plugins'
|
} from './utils/plugins'
|
||||||
import { VueAxios } from './utils/request'
|
import { VueAxios } from './utils/request'
|
||||||
import directives from './utils/directives'
|
import directives from './utils/directives'
|
||||||
@ -55,6 +56,7 @@ vueApp.use(localesPlugin)
|
|||||||
vueApp.use(genericUtilPlugin)
|
vueApp.use(genericUtilPlugin)
|
||||||
vueApp.use(dialogUtilPlugin)
|
vueApp.use(dialogUtilPlugin)
|
||||||
vueApp.use(cpuArchitectureUtilPlugin)
|
vueApp.use(cpuArchitectureUtilPlugin)
|
||||||
|
vueApp.use(imagesUtilPlugin)
|
||||||
vueApp.use(extensions)
|
vueApp.use(extensions)
|
||||||
vueApp.use(directives)
|
vueApp.use(directives)
|
||||||
|
|
||||||
|
|||||||
@ -404,10 +404,11 @@ const user = {
|
|||||||
}).catch(ignored => {})
|
}).catch(ignored => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
api('listUsers', { id: Cookies.get('userid') }).then(response => {
|
api('listUsers', { id: Cookies.get('userid'), showicon: true }).then(response => {
|
||||||
const result = response.listusersresponse.user[0]
|
const result = response.listusersresponse.user[0]
|
||||||
commit('SET_INFO', result)
|
commit('SET_INFO', result)
|
||||||
commit('SET_NAME', result.firstname + ' ' + result.lastname)
|
commit('SET_NAME', result.firstname + ' ' + result.lastname)
|
||||||
|
commit('SET_AVATAR', result.icon?.base64image || '')
|
||||||
store.dispatch('SetCsLatestVersion', result.rolename)
|
store.dispatch('SetCsLatestVersion', result.rolename)
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
reject(error)
|
reject(error)
|
||||||
|
|||||||
@ -338,7 +338,7 @@ export const showIconPlugin = {
|
|||||||
if (resource) {
|
if (resource) {
|
||||||
resourceType = resource
|
resourceType = resource
|
||||||
}
|
}
|
||||||
if (['zone', 'zones', 'template', 'iso', 'account', 'accountuser', 'vm', 'domain', 'project', 'vpc', 'guestnetwork'].includes(resourceType)) {
|
if (['zone', 'zones', 'template', 'iso', 'account', 'accountuser', 'vm', 'domain', 'project', 'vpc', 'guestnetwork', 'guestoscategory'].includes(resourceType)) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -412,6 +412,7 @@ export const resourceTypePlugin = {
|
|||||||
case 'VpnCustomerGateway':
|
case 'VpnCustomerGateway':
|
||||||
case 'AutoScaleVmGroup':
|
case 'AutoScaleVmGroup':
|
||||||
case 'QuotaTariff':
|
case 'QuotaTariff':
|
||||||
|
case 'GuestOsCategory':
|
||||||
return resourceType.toLowerCase()
|
return resourceType.toLowerCase()
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
@ -543,10 +544,24 @@ export const cpuArchitectureUtilPlugin = {
|
|||||||
install (app) {
|
install (app) {
|
||||||
app.config.globalProperties.$fetchCpuArchitectureTypes = function () {
|
app.config.globalProperties.$fetchCpuArchitectureTypes = function () {
|
||||||
const architectures = [
|
const architectures = [
|
||||||
{ id: 'x86_64', name: 'AMD 64 bits (x86_64)' },
|
{ id: 'x86_64', name: 'Intel/AMD 64 bits (x86_64)' },
|
||||||
{ id: 'aarch64', name: 'ARM 64 bits (aarch64)' }
|
{ id: 'aarch64', name: 'ARM 64 bits (aarch64)' }
|
||||||
]
|
]
|
||||||
return architectures.map(item => ({ ...item, description: item.name }))
|
return architectures.map(item => ({ ...item, description: item.name }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const imagesUtilPlugin = {
|
||||||
|
install (app) {
|
||||||
|
app.config.globalProperties.$fetchTemplateTypes = function () {
|
||||||
|
const baseTypes = ['USER', 'VNF']
|
||||||
|
const adminTypes = ['SYSTEM', 'BUILTIN', 'ROUTING']
|
||||||
|
const types = [...baseTypes]
|
||||||
|
if (store.getters.userInfo?.roletype === 'Admin') {
|
||||||
|
types.push(...adminTypes)
|
||||||
|
}
|
||||||
|
return types.map(type => ({ id: type, name: type, description: type }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1261,6 +1261,9 @@ export default {
|
|||||||
}
|
}
|
||||||
var paramName = param.name
|
var paramName = param.name
|
||||||
var extractedParamName = paramName.replace('ids', '').replace('id', '').toLowerCase()
|
var extractedParamName = paramName.replace('ids', '').replace('id', '').toLowerCase()
|
||||||
|
if (extractedParamName.endsWith('ory')) {
|
||||||
|
extractedParamName = extractedParamName.slice(0, -3) + 'orie'
|
||||||
|
}
|
||||||
var params = { listall: true }
|
var params = { listall: true }
|
||||||
for (const filter in filters) {
|
for (const filter in filters) {
|
||||||
params[filter] = filters[filter]
|
params[filter] = filters[filter]
|
||||||
|
|||||||
@ -175,7 +175,7 @@
|
|||||||
class="auth-btn github-auth"
|
class="auth-btn github-auth"
|
||||||
style="height: 38px; width: 185px; padding: 0; margin-bottom: 5px;" >
|
style="height: 38px; width: 185px; padding: 0; margin-bottom: 5px;" >
|
||||||
<img src="/assets/github.svg" style="width: 32px; padding: 5px" />
|
<img src="/assets/github.svg" style="width: 32px; padding: 5px" />
|
||||||
<a-text>Sign in with Github</a-text>
|
<a-typography-text>Sign in with Github</a-typography-text>
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="social-auth" v-if="googleprovider">
|
<div class="social-auth" v-if="googleprovider">
|
||||||
@ -187,7 +187,7 @@
|
|||||||
class="auth-btn google-auth"
|
class="auth-btn google-auth"
|
||||||
style="height: 38px; width: 185px; padding: 0" >
|
style="height: 38px; width: 185px; padding: 0" >
|
||||||
<img src="/assets/google.svg" style="width: 32px; padding: 5px" />
|
<img src="/assets/google.svg" style="width: 32px; padding: 5px" />
|
||||||
<a-text>Sign in with Google</a-text>
|
<a-typography-text>Sign in with Google</a-typography-text>
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -34,72 +34,70 @@
|
|||||||
<div style="margin-top: 15px">
|
<div style="margin-top: 15px">
|
||||||
<span>{{ $t('message.select.a.zone') }}</span><br/>
|
<span>{{ $t('message.select.a.zone') }}</span><br/>
|
||||||
<a-form-item :label="$t('label.zoneid')" name="zoneid" ref="zoneid">
|
<a-form-item :label="$t('label.zoneid')" name="zoneid" ref="zoneid">
|
||||||
<div v-if="zones.length <= 8">
|
<zone-block-radio-group-select
|
||||||
<a-row type="flex" :gutter="[16,18]" justify="start">
|
:items="zones"
|
||||||
<div v-for="(zoneItem, idx) in zones" :key="idx">
|
:selectedValue="form.zoneid"
|
||||||
<a-radio-group
|
@change="onSelectZoneId" />
|
||||||
:key="idx"
|
|
||||||
:size="large"
|
|
||||||
v-model:value="form.zoneid"
|
|
||||||
@change="onSelectZoneId(zoneItem.id)">
|
|
||||||
<a-col :span="6">
|
|
||||||
<a-radio-button
|
|
||||||
:value="zoneItem.id"
|
|
||||||
style="border-width: 2px"
|
|
||||||
class="zone-radio-button">
|
|
||||||
<span>
|
|
||||||
<resource-icon
|
|
||||||
v-if="zoneItem && zoneItem.icon && zoneItem.icon.base64image"
|
|
||||||
:image="zoneItem.icon.base64image"
|
|
||||||
size="2x" />
|
|
||||||
<global-outlined size="2x" v-else />
|
|
||||||
{{ zoneItem.name }}
|
|
||||||
</span>
|
|
||||||
</a-radio-button>
|
|
||||||
</a-col>
|
|
||||||
</a-radio-group>
|
|
||||||
</div>
|
|
||||||
</a-row>
|
|
||||||
</div>
|
|
||||||
<a-select
|
|
||||||
v-else
|
|
||||||
v-model:value="form.zoneid"
|
|
||||||
showSearch
|
|
||||||
optionFilterProp="label"
|
|
||||||
:filterOption="(input, option) => {
|
|
||||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
||||||
}"
|
|
||||||
@change="onSelectZoneId"
|
|
||||||
:loading="loading.zones"
|
|
||||||
v-focus="true"
|
|
||||||
>
|
|
||||||
<a-select-option v-for="zone1 in zones" :key="zone1.id" :label="zone1.name">
|
|
||||||
<span>
|
|
||||||
<resource-icon v-if="zone1.icon && zone1.icon.base64image" :image="zone1.icon.base64image" size="1x" style="margin-right: 5px"/>
|
|
||||||
<global-outlined v-else style="margin-right: 5px" />
|
|
||||||
{{ zone1.name }}
|
|
||||||
</span>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-step>
|
</a-step>
|
||||||
<a-step
|
<a-step
|
||||||
:title="$t('label.template')"
|
v-if="!zoneSelected || isZoneSelectedMultiArch"
|
||||||
|
:title="$t('label.arch')"
|
||||||
:status="zoneSelected ? 'process' : 'wait'">
|
:status="zoneSelected ? 'process' : 'wait'">
|
||||||
<template #description>
|
<template #description>
|
||||||
<div v-if="zoneSelected" style="margin-top: 15px">
|
<div v-if="zoneSelected" style="margin-top: 15px">
|
||||||
|
{{ $t('message.instance.architecture') }}
|
||||||
|
<block-radio-group-select
|
||||||
|
style="margin-top: 5px;"
|
||||||
|
:items="architectureTypes.opts"
|
||||||
|
:selectedValue="selectedArchitecture"
|
||||||
|
@change="changeArchitecture">
|
||||||
|
<template #radio-option="{ item }">
|
||||||
|
<span>{{ item.name || item.description }}</span>
|
||||||
|
</template>
|
||||||
|
<template #select-option="{ item }">
|
||||||
|
<span>{{ item.name || item.description }}</span>
|
||||||
|
</template>
|
||||||
|
</block-radio-group-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-step>
|
||||||
|
<a-step
|
||||||
|
:title="$t('label.template.select')"
|
||||||
|
:status="zoneSelected ? 'process' : 'wait'">
|
||||||
|
<template #description>
|
||||||
|
<div v-if="zoneSelected" style="margin-top: 15px">
|
||||||
|
<os-based-image-selection
|
||||||
|
v-if="isModernImageSelection"
|
||||||
|
:imageTypeSelectionAllowed="false"
|
||||||
|
:imagePreSelected="!!this.queryTemplateId"
|
||||||
|
:guestOsCategoriesSelectionDisallowed="!this.queryGuestOsCategoryId && !!this.queryTemplateId"
|
||||||
|
:guestOsCategories="options.guestOsCategories"
|
||||||
|
:guestOsCategoriesLoading="loading.guestOsCategories"
|
||||||
|
:selectedGuestOsCategoryId="form.guestoscategoryid"
|
||||||
|
:imageItems="options.templates"
|
||||||
|
:imagesLoading="loading.templates"
|
||||||
|
:diskSizeSelectionDeployAsIsMessageVisible="template && template.deployasis"
|
||||||
|
:rootDiskOverrideDisabled="rootDiskSizeFixed > 0 || (template && template.deployasis) || showOverrideDiskOfferingOption"
|
||||||
|
:rootDiskOverrideChecked="form.rootdisksizeitem"
|
||||||
|
:filterOption="filterOption"
|
||||||
|
:preFillContent="dataPreFill"
|
||||||
|
@change-guest-os-category="onSelectGuestOsCategory"
|
||||||
|
@handle-image-search-filter="($event) => fetchAllTemplates($event)"
|
||||||
|
@update-image="updateFieldValue"
|
||||||
|
@update-disk-size="updateFieldValue" />
|
||||||
<a-card
|
<a-card
|
||||||
:tabList="tabList"
|
v-else
|
||||||
:activeTabKey="tabKey"
|
:tabList="imageTypeList"
|
||||||
@tabChange="key => onTabChange(key, 'tabKey')">
|
:activeTabKey="imageType">
|
||||||
<div v-if="tabKey === 'templateid'">
|
<div>
|
||||||
{{ $t('message.template.desc') }}
|
{{ $t('message.template.desc') }}
|
||||||
<template-iso-selection
|
<template-iso-selection
|
||||||
input-decorator="templateid"
|
input-decorator="templateid"
|
||||||
:items="options.templates"
|
:items="options.templates"
|
||||||
:selected="tabKey"
|
:selected="imageType"
|
||||||
:loading="loading.templates"
|
:loading="loading.templates"
|
||||||
:preFillContent="dataPreFill"
|
:preFillContent="dataPreFill"
|
||||||
:key="templateKey"
|
:key="templateKey"
|
||||||
@ -109,10 +107,10 @@
|
|||||||
{{ $t('label.override.rootdisk.size') }}
|
{{ $t('label.override.rootdisk.size') }}
|
||||||
<a-switch
|
<a-switch
|
||||||
v-model:checked="form.rootdisksizeitem"
|
v-model:checked="form.rootdisksizeitem"
|
||||||
:disabled="rootDiskSizeFixed > 0 || template.deployasis || showOverrideDiskOfferingOption"
|
:disabled="rootDiskSizeFixed > 0 || (template && template.deployasis) || showOverrideDiskOfferingOption"
|
||||||
@change="val => { showRootDiskSizeChanger = val }"
|
@change="val => { showRootDiskSizeChanger = val }"
|
||||||
style="margin-left: 10px;"/>
|
style="margin-left: 10px;"/>
|
||||||
<div v-if="template.deployasis"> {{ $t('message.deployasis') }} </div>
|
<div v-if="template && template.deployasis"> {{ $t('message.deployasis') }} </div>
|
||||||
</div>
|
</div>
|
||||||
<disk-size-selection
|
<disk-size-selection
|
||||||
v-if="showRootDiskSizeChanger"
|
v-if="showRootDiskSizeChanger"
|
||||||
@ -220,7 +218,7 @@
|
|||||||
<span v-if="serviceOffering && !serviceOffering.diskofferingstrictness">
|
<span v-if="serviceOffering && !serviceOffering.diskofferingstrictness">
|
||||||
<a-step
|
<a-step
|
||||||
:status="zoneSelected ? 'process' : 'wait'"
|
:status="zoneSelected ? 'process' : 'wait'"
|
||||||
v-if="!template.deployasis && template.childtemplates && template.childtemplates.length > 0" >
|
v-if="template && !template.deployasis && template.childtemplates && template.childtemplates.length > 0" >
|
||||||
<template #description>
|
<template #description>
|
||||||
<div v-if="zoneSelected">
|
<div v-if="zoneSelected">
|
||||||
<multi-disk-selection
|
<multi-disk-selection
|
||||||
@ -244,7 +242,7 @@
|
|||||||
:value="overrideDiskOffering ? overrideDiskOffering.id : ''"
|
:value="overrideDiskOffering ? overrideDiskOffering.id : ''"
|
||||||
:loading="loading.diskOfferings"
|
:loading="loading.diskOfferings"
|
||||||
:preFillContent="dataPreFill"
|
:preFillContent="dataPreFill"
|
||||||
:isIsoSelected="tabKey==='isoid'"
|
:isIsoSelected="imageType==='isoid'"
|
||||||
:isRootDiskOffering="true"
|
:isRootDiskOffering="true"
|
||||||
@on-selected-root-disk-size="onSelectRootDiskSize"
|
@on-selected-root-disk-size="onSelectRootDiskSize"
|
||||||
@select-disk-offering-item="($event) => updateOverrideDiskOffering($event)"
|
@select-disk-offering-item="($event) => updateOverrideDiskOffering($event)"
|
||||||
@ -273,7 +271,7 @@
|
|||||||
<a-step
|
<a-step
|
||||||
:title="$t('label.data.disk')"
|
:title="$t('label.data.disk')"
|
||||||
:status="zoneSelected ? 'process' : 'wait'"
|
:status="zoneSelected ? 'process' : 'wait'"
|
||||||
v-if="!template.deployasis && template.childtemplates && template.childtemplates.length > 0" >
|
v-if="template && !template.deployasis && template.childtemplates && template.childtemplates.length > 0" >
|
||||||
<template #description>
|
<template #description>
|
||||||
<div v-if="zoneSelected">
|
<div v-if="zoneSelected">
|
||||||
<multi-disk-selection
|
<multi-disk-selection
|
||||||
@ -286,7 +284,7 @@
|
|||||||
</a-step>
|
</a-step>
|
||||||
<a-step
|
<a-step
|
||||||
v-else
|
v-else
|
||||||
:title="tabKey === 'templateid' ? $t('label.data.disk') : $t('label.disk.size')"
|
:title="imageType === 'templateid' ? $t('label.data.disk') : $t('label.disk.size')"
|
||||||
:status="zoneSelected ? 'process' : 'wait'">
|
:status="zoneSelected ? 'process' : 'wait'">
|
||||||
<template #description>
|
<template #description>
|
||||||
<div v-if="zoneSelected">
|
<div v-if="zoneSelected">
|
||||||
@ -305,7 +303,7 @@
|
|||||||
:value="diskOffering ? diskOffering.id : ''"
|
:value="diskOffering ? diskOffering.id : ''"
|
||||||
:loading="loading.diskOfferings"
|
:loading="loading.diskOfferings"
|
||||||
:preFillContent="dataPreFill"
|
:preFillContent="dataPreFill"
|
||||||
:isIsoSelected="tabKey==='isoid'"
|
:isIsoSelected="imageType==='isoid'"
|
||||||
@on-selected-disk-size="onSelectDiskSize"
|
@on-selected-disk-size="onSelectDiskSize"
|
||||||
@select-disk-offering-item="($event) => updateDiskOffering($event)"
|
@select-disk-offering-item="($event) => updateDiskOffering($event)"
|
||||||
@handle-search-filter="($event) => handleSearchFilter('diskOfferings', $event)"
|
@handle-search-filter="($event) => handleSearchFilter('diskOfferings', $event)"
|
||||||
@ -768,13 +766,13 @@
|
|||||||
</template>
|
</template>
|
||||||
<a-card>
|
<a-card>
|
||||||
<div v-if="this.template && this.template.userdataid">
|
<div v-if="this.template && this.template.userdataid">
|
||||||
<a-text type="primary">
|
<a-typography-text>
|
||||||
Userdata "{{ $t(this.template.userdataname) }}" is linked with template "{{ $t(this.template.name) }}" with override policy "{{ $t(this.template.userdatapolicy) }}"
|
Userdata "{{ $t(this.template.userdataname) }}" is linked with template "{{ $t(this.template.name) }}" with override policy "{{ $t(this.template.userdatapolicy) }}"
|
||||||
</a-text><br/><br/>
|
</a-typography-text><br/><br/>
|
||||||
<div v-if="templateUserDataParams.length > 0 && !doUserdataOverride">
|
<div v-if="templateUserDataParams.length > 0 && !doUserdataOverride">
|
||||||
<a-text type="primary" v-if="this.template && this.template.userdataid && templateUserDataParams.length > 0">
|
<a-typography-text v-if="this.template && this.template.userdataid && templateUserDataParams.length > 0">
|
||||||
Enter the values for the variables in userdata
|
Enter the values for the variables in userdata
|
||||||
</a-text>
|
</a-typography-text>
|
||||||
<a-input-group>
|
<a-input-group>
|
||||||
<a-table
|
<a-table
|
||||||
size="small"
|
size="small"
|
||||||
@ -1034,12 +1032,15 @@ import eventBus from '@/config/eventBus'
|
|||||||
|
|
||||||
import InfoCard from '@/components/view/InfoCard'
|
import InfoCard from '@/components/view/InfoCard'
|
||||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
|
import ZoneBlockRadioGroupSelect from '@views/compute/wizard/ZoneBlockRadioGroupSelect.vue'
|
||||||
|
import BlockRadioGroupSelect from '@/components/widgets/BlockRadioGroupSelect'
|
||||||
import ComputeOfferingSelection from '@views/compute/wizard/ComputeOfferingSelection'
|
import ComputeOfferingSelection from '@views/compute/wizard/ComputeOfferingSelection'
|
||||||
import ComputeSelection from '@views/compute/wizard/ComputeSelection'
|
import ComputeSelection from '@views/compute/wizard/ComputeSelection'
|
||||||
import DiskOfferingSelection from '@views/compute/wizard/DiskOfferingSelection'
|
import DiskOfferingSelection from '@views/compute/wizard/DiskOfferingSelection'
|
||||||
import DiskSizeSelection from '@views/compute/wizard/DiskSizeSelection'
|
import DiskSizeSelection from '@views/compute/wizard/DiskSizeSelection'
|
||||||
import MultiDiskSelection from '@views/compute/wizard/MultiDiskSelection'
|
import MultiDiskSelection from '@views/compute/wizard/MultiDiskSelection'
|
||||||
import TemplateIsoSelection from '@views/compute/wizard/TemplateIsoSelection'
|
import TemplateIsoSelection from '@views/compute/wizard/TemplateIsoSelection'
|
||||||
|
import OsBasedImageSelection from '@views/compute/wizard/OsBasedImageSelection'
|
||||||
import AffinityGroupSelection from '@views/compute/wizard/AffinityGroupSelection'
|
import AffinityGroupSelection from '@views/compute/wizard/AffinityGroupSelection'
|
||||||
import NetworkSelection from '@views/compute/wizard/NetworkSelection'
|
import NetworkSelection from '@views/compute/wizard/NetworkSelection'
|
||||||
import NetworkConfiguration from '@views/compute/wizard/NetworkConfiguration'
|
import NetworkConfiguration from '@views/compute/wizard/NetworkConfiguration'
|
||||||
@ -1057,6 +1058,10 @@ const STATUS_FAILED = 'error'
|
|||||||
export default {
|
export default {
|
||||||
name: 'Wizard',
|
name: 'Wizard',
|
||||||
components: {
|
components: {
|
||||||
|
InfoCard,
|
||||||
|
ResourceIcon,
|
||||||
|
ZoneBlockRadioGroupSelect,
|
||||||
|
BlockRadioGroupSelect,
|
||||||
SshKeyPairSelection,
|
SshKeyPairSelection,
|
||||||
UserDataSelection,
|
UserDataSelection,
|
||||||
NetworkConfiguration,
|
NetworkConfiguration,
|
||||||
@ -1064,14 +1069,13 @@ export default {
|
|||||||
LoadBalancerSelection,
|
LoadBalancerSelection,
|
||||||
AffinityGroupSelection,
|
AffinityGroupSelection,
|
||||||
TemplateIsoSelection,
|
TemplateIsoSelection,
|
||||||
|
OsBasedImageSelection,
|
||||||
DiskSizeSelection,
|
DiskSizeSelection,
|
||||||
MultiDiskSelection,
|
MultiDiskSelection,
|
||||||
DiskOfferingSelection,
|
DiskOfferingSelection,
|
||||||
InfoCard,
|
|
||||||
ComputeOfferingSelection,
|
ComputeOfferingSelection,
|
||||||
ComputeSelection,
|
ComputeSelection,
|
||||||
SecurityGroupSelection,
|
SecurityGroupSelection,
|
||||||
ResourceIcon,
|
|
||||||
TooltipLabel,
|
TooltipLabel,
|
||||||
InstanceNicsNetworkSelectListView
|
InstanceNicsNetworkSelectListView
|
||||||
},
|
},
|
||||||
@ -1103,7 +1107,10 @@ export default {
|
|||||||
},
|
},
|
||||||
zoneId: '',
|
zoneId: '',
|
||||||
zoneSelected: false,
|
zoneSelected: false,
|
||||||
|
isZoneSelectedMultiArch: false,
|
||||||
dynamicscalingenabled: true,
|
dynamicscalingenabled: true,
|
||||||
|
imageType: 'templateid',
|
||||||
|
imageSearchFilters: null,
|
||||||
templateKey: 0,
|
templateKey: 0,
|
||||||
showRegisteredUserdata: true,
|
showRegisteredUserdata: true,
|
||||||
doUserdataOverride: false,
|
doUserdataOverride: false,
|
||||||
@ -1126,6 +1133,7 @@ export default {
|
|||||||
disksize: null
|
disksize: null
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
|
guestOsCategories: [],
|
||||||
templates: {},
|
templates: {},
|
||||||
serviceOfferings: [],
|
serviceOfferings: [],
|
||||||
diskOfferings: [],
|
diskOfferings: [],
|
||||||
@ -1139,6 +1147,7 @@ export default {
|
|||||||
rowCount: {},
|
rowCount: {},
|
||||||
loading: {
|
loading: {
|
||||||
deploy: false,
|
deploy: false,
|
||||||
|
guestOsCategories: false,
|
||||||
templates: false,
|
templates: false,
|
||||||
serviceOfferings: false,
|
serviceOfferings: false,
|
||||||
diskOfferings: false,
|
diskOfferings: false,
|
||||||
@ -1251,16 +1260,9 @@ export default {
|
|||||||
templateUserDataParams: [],
|
templateUserDataParams: [],
|
||||||
templateUserDataValues: {},
|
templateUserDataValues: {},
|
||||||
overrideDiskOffering: {},
|
overrideDiskOffering: {},
|
||||||
templateFilter: [
|
|
||||||
'featured',
|
|
||||||
'community',
|
|
||||||
'selfexecutable',
|
|
||||||
'sharedexecutable'
|
|
||||||
],
|
|
||||||
initDataConfig: {},
|
initDataConfig: {},
|
||||||
defaultNetworkId: '',
|
defaultNetworkId: '',
|
||||||
dataNetworkCreated: [],
|
dataNetworkCreated: [],
|
||||||
tabKey: 'templateid',
|
|
||||||
userdataTabKey: 'userdataregistered',
|
userdataTabKey: 'userdataregistered',
|
||||||
dataPreFill: {},
|
dataPreFill: {},
|
||||||
showDetails: false,
|
showDetails: false,
|
||||||
@ -1280,7 +1282,9 @@ export default {
|
|||||||
zones: [],
|
zones: [],
|
||||||
selectedZone: '',
|
selectedZone: '',
|
||||||
formModel: {},
|
formModel: {},
|
||||||
nicToNetworkSelection: []
|
nicToNetworkSelection: [],
|
||||||
|
selectedArchitecture: null,
|
||||||
|
architectureTypes: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -1380,7 +1384,7 @@ export default {
|
|||||||
options: {
|
options: {
|
||||||
zoneid: _.get(this.zone, 'id'),
|
zoneid: _.get(this.zone, 'id'),
|
||||||
networkid: this.defaultNetworkId,
|
networkid: this.defaultNetworkId,
|
||||||
id: this.lbRuleId,
|
id: this.queryLbRuleId,
|
||||||
projectid: store.getters.project ? store.getters.project.id : null,
|
projectid: store.getters.project ? store.getters.project.id : null,
|
||||||
domainid: store.getters.project && store.getters.project.id ? null : store.getters.userInfo.domainid,
|
domainid: store.getters.project && store.getters.project.id ? null : store.getters.userInfo.domainid,
|
||||||
account: store.getters.project && store.getters.project.id ? null : store.getters.userInfo.account,
|
account: store.getters.project && store.getters.project.id ? null : store.getters.userInfo.account,
|
||||||
@ -1389,6 +1393,18 @@ export default {
|
|||||||
keyword: undefined,
|
keyword: undefined,
|
||||||
showIcon: true
|
showIcon: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
guestOsCategories: {
|
||||||
|
list: 'listOsCategories',
|
||||||
|
options: {
|
||||||
|
zoneid: _.get(this.zone, 'id'),
|
||||||
|
isfeatured: true,
|
||||||
|
isiso: _.get(this.form, 'imagetype') === 'isoid',
|
||||||
|
arch: this.selectedArchitecture,
|
||||||
|
isvnf: false,
|
||||||
|
showicon: true
|
||||||
|
},
|
||||||
|
field: 'guestoscategoryid'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1406,21 +1422,29 @@ export default {
|
|||||||
templateConfigurationExists () {
|
templateConfigurationExists () {
|
||||||
return this.vm.templateid && this.templateConfigurations && this.templateConfigurations.length > 0
|
return this.vm.templateid && this.templateConfigurations && this.templateConfigurations.length > 0
|
||||||
},
|
},
|
||||||
templateId () {
|
queryZoneId () {
|
||||||
|
return this.$route.query.zoneid || null
|
||||||
|
},
|
||||||
|
queryArchId () {
|
||||||
|
return this.$route.query.arch || null
|
||||||
|
},
|
||||||
|
queryTemplateId () {
|
||||||
return this.$route.query.templateid || null
|
return this.$route.query.templateid || null
|
||||||
},
|
},
|
||||||
networkId () {
|
queryNetworkId () {
|
||||||
return this.$route.query.networkid || null
|
return this.$route.query.networkid || null
|
||||||
},
|
},
|
||||||
lbRuleId () {
|
queryGuestOsCategoryId () {
|
||||||
|
return this.$route.query.oscategoryid || null
|
||||||
|
},
|
||||||
|
queryLbRuleId () {
|
||||||
return this.$route.query.lbruleid || null
|
return this.$route.query.lbruleid || null
|
||||||
},
|
},
|
||||||
tabList () {
|
imageTypeList () {
|
||||||
const tabList = [{
|
return [{
|
||||||
key: 'templateid',
|
key: 'templateid',
|
||||||
tab: this.$t('label.templates')
|
tab: this.$t('label.templates')
|
||||||
}]
|
}]
|
||||||
return tabList
|
|
||||||
},
|
},
|
||||||
userdataTabList () {
|
userdataTabList () {
|
||||||
let tabList = []
|
let tabList = []
|
||||||
@ -1451,6 +1475,18 @@ export default {
|
|||||||
},
|
},
|
||||||
isCustomizedIOPS () {
|
isCustomizedIOPS () {
|
||||||
return this.rootDiskSelected?.iscustomizediops || this.serviceOffering?.iscustomizediops || false
|
return this.rootDiskSelected?.iscustomizediops || this.serviceOffering?.iscustomizediops || false
|
||||||
|
},
|
||||||
|
isModernImageSelection () {
|
||||||
|
return this.$config.imageSelectionInterface === undefined || this.$config.imageSelectionInterface === 'modern'
|
||||||
|
},
|
||||||
|
imageSelection () {
|
||||||
|
return this.isModernImageSelection ? 'modern' : 'legacy'
|
||||||
|
},
|
||||||
|
showUserCategoryForModernImageSelection () {
|
||||||
|
return this.$config.showUserCategoryForModernImageSelection === undefined || this.$config.showUserCategoryForModernImageSelection
|
||||||
|
},
|
||||||
|
showAllCategoryForModernImageSelection () {
|
||||||
|
return this.$config.showAllCategoryForModernImageSelection
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -1466,7 +1502,7 @@ export default {
|
|||||||
Object.keys(vmgroupConfig).forEach(field => {
|
Object.keys(vmgroupConfig).forEach(field => {
|
||||||
this.vm[field] = this.vmgroupConfig[field]
|
this.vm[field] = this.vmgroupConfig[field]
|
||||||
})
|
})
|
||||||
this.template = ''
|
this.template = null
|
||||||
for (const key in this.options.templates) {
|
for (const key in this.options.templates) {
|
||||||
var template = _.find(_.get(this.options.templates[key], 'template', []), (option) => option.id === vmgroupConfig.templateid)
|
var template = _.find(_.get(this.options.templates[key], 'template', []), (option) => option.id === vmgroupConfig.templateid)
|
||||||
if (template) {
|
if (template) {
|
||||||
@ -1545,7 +1581,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.template.deployasis && this.template.childtemplates && this.template.childtemplates.length > 0) {
|
if (this.template && !this.template.deployasis && this.template.childtemplates && this.template.childtemplates.length > 0) {
|
||||||
this.vm.diskofferingid = ''
|
this.vm.diskofferingid = ''
|
||||||
this.vm.diskofferingname = ''
|
this.vm.diskofferingname = ''
|
||||||
this.vm.diskofferingsize = ''
|
this.vm.diskofferingsize = ''
|
||||||
@ -1766,6 +1802,27 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getImageFilters (params, forReset) {
|
||||||
|
if (this.isModernImageSelection) {
|
||||||
|
if (this.form.guestoscategoryid === '0') {
|
||||||
|
return ['self']
|
||||||
|
}
|
||||||
|
if (this.isModernImageSelection && params && !forReset) {
|
||||||
|
if (params.featured) {
|
||||||
|
return ['featured']
|
||||||
|
} else if (params.public) {
|
||||||
|
return ['community']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.isNormalAndDomainUser ? ['executable'] : ['all']
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'featured',
|
||||||
|
'community',
|
||||||
|
'selfexecutable',
|
||||||
|
'sharedexecutable'
|
||||||
|
]
|
||||||
|
},
|
||||||
getPropertyQualifiers (qualifiers, type) {
|
getPropertyQualifiers (qualifiers, type) {
|
||||||
var result = ''
|
var result = ''
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -1805,18 +1862,25 @@ export default {
|
|||||||
let zones = []
|
let zones = []
|
||||||
let apiName = ''
|
let apiName = ''
|
||||||
const params = {}
|
const params = {}
|
||||||
if (this.templateId) {
|
if (this.queryZoneId) {
|
||||||
|
zones.push(this.queryZoneId)
|
||||||
|
if (this.queryTemplateId) {
|
||||||
|
this.dataPreFill.templateid = this.queryTemplateId
|
||||||
|
}
|
||||||
|
return resolve(zones)
|
||||||
|
} else if (this.queryTemplateId) {
|
||||||
apiName = 'listTemplates'
|
apiName = 'listTemplates'
|
||||||
params.listall = true
|
params.listall = true
|
||||||
params.templatefilter = this.isNormalAndDomainUser ? 'executable' : 'all'
|
params.templatefilter = this.isNormalAndDomainUser ? 'executable' : 'all'
|
||||||
params.id = this.templateId
|
params.id = this.queryTemplateId
|
||||||
} else if (this.networkId) {
|
this.dataPreFill.templateid = this.queryTemplateId
|
||||||
|
} else if (this.queryNetworkId) {
|
||||||
params.listall = true
|
params.listall = true
|
||||||
params.id = this.networkId
|
params.id = this.queryNetworkId
|
||||||
apiName = 'listNetworks'
|
apiName = 'listNetworks'
|
||||||
} else if (this.lbRuleId) {
|
} else if (this.queryLbRuleId) {
|
||||||
params.listall = true
|
params.listall = true
|
||||||
params.id = this.lbRuleId
|
params.id = this.queryLbRuleId
|
||||||
apiName = 'listLoadBalancerRules'
|
apiName = 'listLoadBalancerRules'
|
||||||
}
|
}
|
||||||
if (!apiName) return resolve(zones)
|
if (!apiName) return resolve(zones)
|
||||||
@ -1840,6 +1904,10 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
async fetchData () {
|
async fetchData () {
|
||||||
|
this.architectureTypes.opts = this.$fetchCpuArchitectureTypes()
|
||||||
|
if (this.queryArchId) {
|
||||||
|
this.architectureTypes.opts = this.architectureTypes.opts.filter(o => o.id === this.queryArchId)
|
||||||
|
}
|
||||||
const zones = await this.fetchZoneByQuery()
|
const zones = await this.fetchZoneByQuery()
|
||||||
if (zones && zones.length === 1) {
|
if (zones && zones.length === 1) {
|
||||||
this.selectedZone = zones[0]
|
this.selectedZone = zones[0]
|
||||||
@ -1986,25 +2054,18 @@ export default {
|
|||||||
},
|
},
|
||||||
updateFieldValue (name, value) {
|
updateFieldValue (name, value) {
|
||||||
if (name === 'templateid') {
|
if (name === 'templateid') {
|
||||||
this.tabKey = 'templateid'
|
|
||||||
this.form.templateid = value
|
this.form.templateid = value
|
||||||
this.resetFromTemplateConfiguration()
|
this.resetFromTemplateConfiguration()
|
||||||
let template = ''
|
let template = ''
|
||||||
for (const key in this.options.templates) {
|
for (const entry of Object.values(this.options.templates)) {
|
||||||
var t = _.find(_.get(this.options.templates[key], 'template', []), (option) => option.id === value)
|
template = entry?.template.find(option => option.id === value) || null
|
||||||
if (t) {
|
if (template) {
|
||||||
this.template = t
|
this.template = template
|
||||||
this.templateConfigurations = []
|
|
||||||
this.selectedTemplateConfiguration = {}
|
|
||||||
this.templateNics = []
|
|
||||||
this.templateLicenses = []
|
|
||||||
this.templateProperties = {}
|
|
||||||
this.updateTemplateParameters()
|
|
||||||
template = t
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (template) {
|
if (template) {
|
||||||
|
this.resetTemplateAssociatedResources()
|
||||||
var size = template.size / (1024 * 1024 * 1024) || 0 // bytes to GB
|
var size = template.size / (1024 * 1024 * 1024) || 0 // bytes to GB
|
||||||
this.dataPreFill.minrootdisksize = Math.ceil(size)
|
this.dataPreFill.minrootdisksize = Math.ceil(size)
|
||||||
this.updateTemplateLinkedUserData(this.template.userdataid)
|
this.updateTemplateLinkedUserData(this.template.userdataid)
|
||||||
@ -2392,6 +2453,58 @@ export default {
|
|||||||
getText (option) {
|
getText (option) {
|
||||||
return _.get(option, 'displaytext', _.get(option, 'name'))
|
return _.get(option, 'displaytext', _.get(option, 'name'))
|
||||||
},
|
},
|
||||||
|
fetchGuestOsCategories (skipFetchImages) {
|
||||||
|
const key = 'guestOsCategories'
|
||||||
|
const params = this.params[key]
|
||||||
|
if (this.queryGuestOsCategoryId) {
|
||||||
|
params.options.id = this.queryGuestOsCategoryId
|
||||||
|
} else if (this.queryTemplateId) {
|
||||||
|
this.fetchAllTemplates()
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
return this.fetchOptions(params, key, ['zones'])
|
||||||
|
.then((res) => {
|
||||||
|
if (!this.options.guestOsCategories) {
|
||||||
|
this.options.guestOsCategories = []
|
||||||
|
}
|
||||||
|
if (!this.queryGuestOsCategoryId) {
|
||||||
|
if (this.showUserCategoryForModernImageSelection) {
|
||||||
|
const userCategory = {
|
||||||
|
id: '0',
|
||||||
|
name: this.$t('label.user')
|
||||||
|
}
|
||||||
|
if (this.$store.getters.avatar) {
|
||||||
|
userCategory.icon = {
|
||||||
|
base64image: this.$store.getters.avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.options.guestOsCategories.push(userCategory)
|
||||||
|
}
|
||||||
|
if (this.showAllCategoryForModernImageSelection) {
|
||||||
|
this.options.guestOsCategories.push({
|
||||||
|
id: '-1',
|
||||||
|
name: this.$t('label.all')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.form.guestoscategoryid = this.options.guestOsCategories[0].id
|
||||||
|
if (skipFetchImages) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.fetchAllTemplates()
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error('Error fetching guestOsCategories:', e)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
changeArchitecture (arch) {
|
||||||
|
this.selectedArchitecture = arch
|
||||||
|
if (this.isModernImageSelection) {
|
||||||
|
this.fetchGuestOsCategories()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.fetchAllTemplates()
|
||||||
|
},
|
||||||
async handleSubmit (e) {
|
async handleSubmit (e) {
|
||||||
console.log('wizard submit')
|
console.log('wizard submit')
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@ -2552,7 +2665,7 @@ export default {
|
|||||||
|
|
||||||
if (this.showRootDiskSizeChanger && values.rootdisksize && values.rootdisksize > 0) {
|
if (this.showRootDiskSizeChanger && values.rootdisksize && values.rootdisksize > 0) {
|
||||||
createVmGroupData.rootdisksize = values.rootdisksize
|
createVmGroupData.rootdisksize = values.rootdisksize
|
||||||
} else if (this.rootDiskSizeFixed > 0 && !this.template.deployasis) {
|
} else if (this.rootDiskSizeFixed > 0 && this.template && !this.template.deployasis) {
|
||||||
createVmGroupData.rootdisksize = this.rootDiskSizeFixed
|
createVmGroupData.rootdisksize = this.rootDiskSizeFixed
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2799,72 +2912,86 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
fetchOptions (param, name, exclude) {
|
fetchOptions (param, name, exclude) {
|
||||||
if (exclude && exclude.length > 0) {
|
return new Promise((resolve, reject) => {
|
||||||
if (exclude.includes(name)) {
|
if (exclude && exclude.length > 0 && exclude.includes(name)) {
|
||||||
return
|
return resolve(null)
|
||||||
}
|
}
|
||||||
}
|
this.loading[name] = true
|
||||||
this.loading[name] = true
|
param.loading = true
|
||||||
param.loading = true
|
param.opts = []
|
||||||
param.opts = []
|
const options = param.options || {}
|
||||||
const options = param.options || {}
|
if (!('listall' in options) && !['zones', 'pods', 'clusters', 'hosts', 'dynamicScalingVmConfig', 'hypervisors'].includes(name)) {
|
||||||
if (!('listall' in options) && !['zones', 'pods', 'clusters', 'hosts', 'dynamicScalingVmConfig', 'hypervisors'].includes(name)) {
|
options.listall = true
|
||||||
options.listall = true
|
}
|
||||||
}
|
api(param.list, options).then((response) => {
|
||||||
api(param.list, options).then((response) => {
|
param.loading = false
|
||||||
param.loading = false
|
_.map(response, (responseItem, responseKey) => {
|
||||||
_.map(response, (responseItem, responseKey) => {
|
if (Object.keys(responseItem).length === 0) {
|
||||||
if (Object.keys(responseItem).length === 0) {
|
this.rowCount[name] = 0
|
||||||
this.rowCount[name] = 0
|
this.options[name] = []
|
||||||
this.options[name] = []
|
return resolve(null)
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!responseKey.includes('response')) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_.map(responseItem, (response, key) => {
|
|
||||||
if (key === 'count') {
|
|
||||||
this.rowCount[name] = response
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
param.opts = response
|
if (!responseKey.includes('response')) {
|
||||||
this.options[name] = response
|
return resolve(null)
|
||||||
|
}
|
||||||
|
_.map(responseItem, (response, key) => {
|
||||||
|
if (key === 'count') {
|
||||||
|
this.rowCount[name] = response
|
||||||
|
return
|
||||||
|
}
|
||||||
|
param.opts = response
|
||||||
|
this.options[name] = response
|
||||||
|
|
||||||
if (param.field) {
|
if (param.field) {
|
||||||
this.fillValue(param.field)
|
this.fillValue(param.field)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (name === 'zones') {
|
||||||
|
let zoneid = ''
|
||||||
|
if (this.$route.query.zoneid) {
|
||||||
|
zoneid = this.$route.query.zoneid
|
||||||
|
} else if (this.options.zones.length === 1) {
|
||||||
|
zoneid = this.options.zones[0].id
|
||||||
|
}
|
||||||
|
if (zoneid) {
|
||||||
|
this.form.zoneid = zoneid
|
||||||
|
this.onSelectZoneId(zoneid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
resolve(response)
|
||||||
if (name === 'zones') {
|
}).catch(function (error) {
|
||||||
let zoneid = ''
|
console.log(error.stack)
|
||||||
if (this.$route.query.zoneid) {
|
param.loading = false
|
||||||
zoneid = this.$route.query.zoneid
|
reject(error)
|
||||||
} else if (this.options.zones.length === 1) {
|
}).finally(() => {
|
||||||
zoneid = this.options.zones[0].id
|
this.loading[name] = false
|
||||||
}
|
|
||||||
if (zoneid) {
|
|
||||||
this.form.zoneid = zoneid
|
|
||||||
this.onSelectZoneId(zoneid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}).catch(function (error) {
|
|
||||||
console.log(error.stack)
|
|
||||||
param.loading = false
|
|
||||||
}).finally(() => {
|
|
||||||
this.loading[name] = false
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fetchTemplates (templateFilter, params) {
|
fetchTemplates (templateFilter, params) {
|
||||||
const args = Object.assign({}, params)
|
const args = Object.assign({}, params)
|
||||||
if (args.keyword || args.category !== templateFilter) {
|
if (this.isModernImageSelection && this.form.guestoscategoryid && !['-1', '0'].includes(this.form.guestoscategoryid)) {
|
||||||
|
args.oscategoryid = this.form.guestoscategoryid
|
||||||
|
}
|
||||||
|
if (args.keyword || (args.category && args.category !== templateFilter)) {
|
||||||
args.page = 1
|
args.page = 1
|
||||||
args.pageSize = args.pageSize || 10
|
args.pageSize = args.pageSize || 10
|
||||||
}
|
}
|
||||||
args.zoneid = _.get(this.zone, 'id')
|
args.zoneid = _.get(this.zone, 'id')
|
||||||
|
if (this.isZoneSelectedMultiArch) {
|
||||||
|
args.arch = this.selectedArchitecture
|
||||||
|
}
|
||||||
args.templatefilter = templateFilter
|
args.templatefilter = templateFilter
|
||||||
args.details = 'all'
|
args.details = 'all'
|
||||||
args.showicon = 'true'
|
args.showicon = 'true'
|
||||||
|
args.id = this.queryTemplateId
|
||||||
|
args.isvnf = false
|
||||||
|
|
||||||
|
delete args.category
|
||||||
|
delete args.public
|
||||||
|
delete args.featured
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
api('listTemplates', args).then((response) => {
|
api('listTemplates', args).then((response) => {
|
||||||
@ -2879,14 +3006,16 @@ export default {
|
|||||||
const promises = []
|
const promises = []
|
||||||
const templates = {}
|
const templates = {}
|
||||||
this.loading.templates = true
|
this.loading.templates = true
|
||||||
this.templateFilter.forEach((filter) => {
|
this.imageSearchFilters = params
|
||||||
|
const templateFilters = this.getImageFilters(params)
|
||||||
|
templateFilters.forEach((filter) => {
|
||||||
templates[filter] = { count: 0, template: [] }
|
templates[filter] = { count: 0, template: [] }
|
||||||
promises.push(this.fetchTemplates(filter, params))
|
promises.push(this.fetchTemplates(filter, params))
|
||||||
})
|
})
|
||||||
this.options.templates = templates
|
this.options.templates = templates
|
||||||
Promise.all(promises).then((response) => {
|
Promise.all(promises).then((response) => {
|
||||||
response.forEach((resItem, idx) => {
|
response.forEach((resItem, idx) => {
|
||||||
templates[this.templateFilter[idx]] = _.isEmpty(resItem.listtemplatesresponse) ? { count: 0, template: [] } : resItem.listtemplatesresponse
|
templates[templateFilters[idx]] = _.isEmpty(resItem.listtemplatesresponse) ? { count: 0, template: [] } : resItem.listtemplatesresponse
|
||||||
this.options.templates = { ...templates }
|
this.options.templates = { ...templates }
|
||||||
})
|
})
|
||||||
}).catch((reason) => {
|
}).catch((reason) => {
|
||||||
@ -2898,35 +3027,71 @@ export default {
|
|||||||
filterOption (input, option) {
|
filterOption (input, option) {
|
||||||
return option.label.toUpperCase().indexOf(input.toUpperCase()) >= 0
|
return option.label.toUpperCase().indexOf(input.toUpperCase()) >= 0
|
||||||
},
|
},
|
||||||
|
resetTemplatesList () {
|
||||||
|
const templates = {}
|
||||||
|
const templateFilters = this.getImageFilters(null, true)
|
||||||
|
templateFilters.forEach((filter) => {
|
||||||
|
templates[filter] = { count: 0, template: [] }
|
||||||
|
})
|
||||||
|
this.options.templates = templates
|
||||||
|
},
|
||||||
|
resetTemplateAssociatedResources () {
|
||||||
|
this.templateConfigurations = []
|
||||||
|
this.selectedTemplateConfiguration = {}
|
||||||
|
this.templateNics = []
|
||||||
|
this.templateLicenses = []
|
||||||
|
this.templateProperties = {}
|
||||||
|
},
|
||||||
|
async fetchZoneOptions () {
|
||||||
|
let guestOsFetch = null
|
||||||
|
for (const [name, param] of Object.entries(this.params)) {
|
||||||
|
if (this.queryNetworkId && name === 'networks') {
|
||||||
|
param.options = { id: this.queryNetworkId }
|
||||||
|
}
|
||||||
|
if (name === 'loadbalancers') {
|
||||||
|
if (!this.queryLbRuleId && !this.defaultNetworkId) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (this.queryLbRuleId) {
|
||||||
|
param.options = { id: this.queryLbRuleId }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const shouldLoad = !('isLoad' in param) || param.isLoad
|
||||||
|
if (!shouldLoad) continue
|
||||||
|
if (this.isModernImageSelection && name === 'guestOsCategories') {
|
||||||
|
guestOsFetch = this.fetchGuestOsCategories(true)
|
||||||
|
} else {
|
||||||
|
this.fetchOptions(param, name, ['zones'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isModernImageSelection && guestOsFetch) {
|
||||||
|
await guestOsFetch
|
||||||
|
}
|
||||||
|
this.fetchAllTemplates()
|
||||||
|
this.updateTemplateKey()
|
||||||
|
this.formModel = toRaw(this.form)
|
||||||
|
},
|
||||||
onSelectZoneId (value) {
|
onSelectZoneId (value) {
|
||||||
this.dataPreFill = {}
|
if (this.dataPreFill.zoneid !== value) {
|
||||||
|
this.dataPreFill = {}
|
||||||
|
}
|
||||||
this.zoneId = value
|
this.zoneId = value
|
||||||
this.zone = _.find(this.options.zones, (option) => option.id === value)
|
this.zone = _.find(this.options.zones, (option) => option.id === value)
|
||||||
this.zoneSelected = true
|
this.zoneSelected = true
|
||||||
|
this.isZoneSelectedMultiArch = this.zone.ismultiarch
|
||||||
|
if (this.isZoneSelectedMultiArch) {
|
||||||
|
this.selectedArchitecture = this.architectureTypes.opts[0].id
|
||||||
|
}
|
||||||
this.selectedZone = this.zoneId
|
this.selectedZone = this.zoneId
|
||||||
this.form.zoneid = this.zoneId
|
this.form.zoneid = this.zoneId
|
||||||
this.form.templateid = undefined
|
this.form.templateid = undefined
|
||||||
this.tabKey = 'templateid'
|
this.resetTemplatesList()
|
||||||
_.each(this.params, (param, name) => {
|
this.fetchZoneOptions()
|
||||||
if (this.networkId && name === 'networks') {
|
},
|
||||||
param.options = {
|
onSelectGuestOsCategory (value) {
|
||||||
id: this.networkId
|
this.form.guestoscategoryid = value
|
||||||
}
|
this.fetchAllTemplates(this.imageSearchFilters)
|
||||||
}
|
|
||||||
if (this.lbRuleId && name === 'loadbalancers') {
|
|
||||||
param.options = {
|
|
||||||
id: this.lbRuleId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!('isLoad' in param) || param.isLoad) {
|
|
||||||
this.fetchOptions(param, name, ['zones'])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (this.tabKey === 'templateid') {
|
|
||||||
this.fetchAllTemplates()
|
|
||||||
}
|
|
||||||
this.updateTemplateKey()
|
|
||||||
this.formModel = toRaw(this.form)
|
|
||||||
},
|
},
|
||||||
handleSearchFilter (name, options) {
|
handleSearchFilter (name, options) {
|
||||||
this.params[name].options = { ...this.params[name].options, ...options }
|
this.params[name].options = { ...this.params[name].options, ...options }
|
||||||
@ -3184,7 +3349,7 @@ export default {
|
|||||||
.vm-info-card {
|
.vm-info-card {
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
min-height: 250px;
|
min-height: 250px;
|
||||||
max-height: calc(100vh - 150px);
|
max-height: calc(100vh - 250px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -19,28 +19,35 @@
|
|||||||
<a-form
|
<a-form
|
||||||
v-ctrl-enter="handleSubmit"
|
v-ctrl-enter="handleSubmit"
|
||||||
@finish="handleSubmit"
|
@finish="handleSubmit"
|
||||||
layout="vertical"
|
layout="vertical">
|
||||||
>
|
<a-alert type="warning" show-icon>
|
||||||
<a-alert
|
<template #message>
|
||||||
type="warning"
|
<span style="margin-bottom: 5px" v-html="$t('message.reinstall.vm')" />
|
||||||
show-icon
|
</template>
|
||||||
>
|
|
||||||
<template #message><span
|
|
||||||
style="margin-bottom: 5px"
|
|
||||||
v-html="$t('message.reinstall.vm')"
|
|
||||||
/></template>
|
|
||||||
</a-alert>
|
</a-alert>
|
||||||
<a-form-item>
|
<os-based-image-selection
|
||||||
|
v-if="isModernImageSelection"
|
||||||
|
:imageTypeSelectionAllowed="false"
|
||||||
|
:guestOsCategories="options.guestOsCategories"
|
||||||
|
:guestOsCategoriesLoading="loading.guestOsCategories"
|
||||||
|
:selectedGuestOsCategoryId="selectedGuestOsCategoryId"
|
||||||
|
:imageItems="options.templates"
|
||||||
|
:imagesLoading="loading.templates"
|
||||||
|
:filterOption="filterOption"
|
||||||
|
:preFillContent="dataPreFill"
|
||||||
|
@change-guest-os-category="onSelectGuestOsCategory"
|
||||||
|
@handle-image-search-filter="($event) => fetchAllTemplates($event)"
|
||||||
|
@update-image="updateFieldValue" />
|
||||||
|
<a-form-item v-else>
|
||||||
<template-iso-selection
|
<template-iso-selection
|
||||||
input-decorator="templateid"
|
input-decorator="templateid"
|
||||||
:items="templates"
|
:items="options.templates"
|
||||||
:selected="tabKey"
|
:selected="tabKey"
|
||||||
:loading="loading.templates"
|
:loading="loading.templates"
|
||||||
:preFillContent="dataPrefill"
|
:preFillContent="dataPreFill"
|
||||||
:key="templateKey"
|
:key="templateKey"
|
||||||
@handle-search-filter="($event) => fetchAllTemplates($event)"
|
@handle-search-filter="($event) => fetchAllTemplates($event)"
|
||||||
@update-template-iso="updateFieldValue"
|
@update-template-iso="updateFieldValue" />
|
||||||
/>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<template #label>
|
<template #label>
|
||||||
@ -56,12 +63,12 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="overrideDiskOffering">
|
<a-form-item v-if="overrideDiskOffering">
|
||||||
<disk-offering-selection
|
<disk-offering-selection
|
||||||
:items="diskOfferings"
|
:items="options.diskOfferings"
|
||||||
:row-count="diskOfferingCount"
|
:row-count="count.diskOfferings"
|
||||||
:zoneId="resource.zoneId"
|
:zoneId="resource.zoneId"
|
||||||
:value="diskOffering ? diskOffering.id : ''"
|
:value="diskOffering ? diskOffering.id : ''"
|
||||||
:loading="loading.diskOfferings"
|
:loading="loading.diskOfferings"
|
||||||
:preFillContent="dataPrefill"
|
:preFillContent="dataPreFill"
|
||||||
:isIsoSelected="false"
|
:isIsoSelected="false"
|
||||||
:isRootDiskOffering="true"
|
:isRootDiskOffering="true"
|
||||||
@on-selected-disk-size="onSelectDiskSize"
|
@on-selected-disk-size="onSelectDiskSize"
|
||||||
@ -127,6 +134,7 @@
|
|||||||
import { api } from '@/api'
|
import { api } from '@/api'
|
||||||
import DiskOfferingSelection from '@views/compute/wizard/DiskOfferingSelection'
|
import DiskOfferingSelection from '@views/compute/wizard/DiskOfferingSelection'
|
||||||
import DiskSizeSelection from '@views/compute/wizard/DiskSizeSelection'
|
import DiskSizeSelection from '@views/compute/wizard/DiskSizeSelection'
|
||||||
|
import OsBasedImageSelection from '@views/compute/wizard/OsBasedImageSelection'
|
||||||
import TemplateIsoSelection from '@views/compute/wizard/TemplateIsoSelection'
|
import TemplateIsoSelection from '@views/compute/wizard/TemplateIsoSelection'
|
||||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
@ -137,6 +145,7 @@ export default {
|
|||||||
DiskOfferingSelection,
|
DiskOfferingSelection,
|
||||||
DiskSizeSelection,
|
DiskSizeSelection,
|
||||||
TemplateIsoSelection,
|
TemplateIsoSelection,
|
||||||
|
OsBasedImageSelection,
|
||||||
TooltipLabel
|
TooltipLabel
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@ -151,10 +160,19 @@ export default {
|
|||||||
overrideDiskOffering: false,
|
overrideDiskOffering: false,
|
||||||
overrideDiskSize: false,
|
overrideDiskSize: false,
|
||||||
expungeDisk: false,
|
expungeDisk: false,
|
||||||
selectedDiskOffering: {},
|
selectedGuestOsCategoryId: null,
|
||||||
|
options: {
|
||||||
|
templates: {},
|
||||||
|
diskOfferings: [],
|
||||||
|
guestOsCategories: []
|
||||||
|
},
|
||||||
loading: {
|
loading: {
|
||||||
templates: false,
|
templates: false,
|
||||||
diskOfferings: false
|
diskOfferings: false,
|
||||||
|
guestOsCategories: false
|
||||||
|
},
|
||||||
|
count: {
|
||||||
|
diskOfferings: 0
|
||||||
},
|
},
|
||||||
rootDiskSizeKey: 'details[0].rootdisksize',
|
rootDiskSizeKey: 'details[0].rootdisksize',
|
||||||
minIopsKey: 'details[0].minIops',
|
minIopsKey: 'details[0].minIops',
|
||||||
@ -162,16 +180,11 @@ export default {
|
|||||||
rootdisksize: 0,
|
rootdisksize: 0,
|
||||||
minIops: 0,
|
minIops: 0,
|
||||||
maxIops: 0,
|
maxIops: 0,
|
||||||
templateFilter: [
|
|
||||||
'featured',
|
|
||||||
'community',
|
|
||||||
'selfexecutable',
|
|
||||||
'sharedexecutable'
|
|
||||||
],
|
|
||||||
diskOffering: {},
|
diskOffering: {},
|
||||||
diskOfferingCount: 0,
|
imageSearchFilters: null,
|
||||||
|
templateid: null,
|
||||||
templateKey: 0,
|
templateKey: 0,
|
||||||
dataPrefill: {
|
dataPreFill: {
|
||||||
templateid: this.resource.templateid,
|
templateid: this.resource.templateid,
|
||||||
diskofferingid: this.resource.diskofferingid
|
diskofferingid: this.resource.diskofferingid
|
||||||
}
|
}
|
||||||
@ -183,10 +196,52 @@ export default {
|
|||||||
created () {
|
created () {
|
||||||
this.fetchData()
|
this.fetchData()
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
isNormalAndDomainUser () {
|
||||||
|
return ['DomainAdmin', 'User'].includes(this.$store.getters.userInfo.roletype)
|
||||||
|
},
|
||||||
|
isModernImageSelection () {
|
||||||
|
return this.$config.imageSelectionInterface === undefined || this.$config.imageSelectionInterface === 'modern'
|
||||||
|
},
|
||||||
|
imageSelection () {
|
||||||
|
return this.isModernImageSelection ? 'modern' : 'legacy'
|
||||||
|
},
|
||||||
|
showUserCategoryForModernImageSelection () {
|
||||||
|
return this.$config.showUserCategoryForModernImageSelection === undefined || this.$config.showUserCategoryForModernImageSelection
|
||||||
|
},
|
||||||
|
showAllCategoryForModernImageSelection () {
|
||||||
|
return this.$config.showAllCategoryForModernImageSelection
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fetchData () {
|
fetchData () {
|
||||||
this.fetchDiskOfferings({})
|
this.fetchDiskOfferings({})
|
||||||
this.fetchAllTemplates()
|
if (this.isModernImageSelection) {
|
||||||
|
this.fetchGuestOsCategories()
|
||||||
|
} else {
|
||||||
|
this.fetchAllTemplates()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getImageFilters (params, forReset) {
|
||||||
|
if (this.isModernImageSelection) {
|
||||||
|
if (this.selectedGuestOsCategoryId === '0') {
|
||||||
|
return ['self']
|
||||||
|
}
|
||||||
|
if (this.isModernImageSelection && params && !forReset) {
|
||||||
|
if (params.featured) {
|
||||||
|
return ['featured']
|
||||||
|
} else if (params.public) {
|
||||||
|
return ['community']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.isNormalAndDomainUser ? ['executable'] : ['all']
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'featured',
|
||||||
|
'community',
|
||||||
|
'selfexecutable',
|
||||||
|
'sharedexecutable'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
closeAction () {
|
closeAction () {
|
||||||
this.$emit('close-action')
|
this.$emit('close-action')
|
||||||
@ -244,19 +299,56 @@ export default {
|
|||||||
this.closeAction()
|
this.closeAction()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
fetchGuestOsCategories () {
|
||||||
|
this.loading.guestOsCategories = true
|
||||||
|
const params = {
|
||||||
|
zoneid: this.resource.zoneid,
|
||||||
|
arch: this.resource.arch,
|
||||||
|
isiso: false,
|
||||||
|
featured: true,
|
||||||
|
showicon: true
|
||||||
|
}
|
||||||
|
api('listOsCategories', params).then((response) => {
|
||||||
|
this.options.guestOsCategories = response?.listoscategoriesresponse?.oscategory || []
|
||||||
|
if (this.showUserCategoryForModernImageSelection) {
|
||||||
|
const userCategory = {
|
||||||
|
id: '0',
|
||||||
|
name: this.$t('label.user')
|
||||||
|
}
|
||||||
|
if (this.$store.getters.avatar) {
|
||||||
|
userCategory.icon = {
|
||||||
|
base64image: this.$store.getters.avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.options.guestOsCategories.push(userCategory)
|
||||||
|
}
|
||||||
|
if (this.showAllCategoryForModernImageSelection) {
|
||||||
|
this.options.guestOsCategories.push({
|
||||||
|
id: '-1',
|
||||||
|
name: this.$t('label.all')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.selectedGuestOsCategoryId = this.options.guestOsCategories[0].id
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading.guestOsCategories = false
|
||||||
|
this.fetchAllTemplates()
|
||||||
|
})
|
||||||
|
},
|
||||||
fetchAllTemplates (params) {
|
fetchAllTemplates (params) {
|
||||||
const promises = []
|
const promises = []
|
||||||
const templates = {}
|
const templates = {}
|
||||||
this.loading.templates = true
|
this.loading.templates = true
|
||||||
this.templateFilter.forEach((filter) => {
|
this.imageSearchFilters = params
|
||||||
|
const templateFilters = this.getImageFilters(params)
|
||||||
|
templateFilters.forEach((filter) => {
|
||||||
templates[filter] = { count: 0, template: [] }
|
templates[filter] = { count: 0, template: [] }
|
||||||
promises.push(this.fetchTemplates(filter, params))
|
promises.push(this.fetchTemplates(filter, params))
|
||||||
})
|
})
|
||||||
this.templates = templates
|
this.options.templates = templates
|
||||||
Promise.all(promises).then((response) => {
|
Promise.all(promises).then((response) => {
|
||||||
response.forEach((resItem, idx) => {
|
response.forEach((resItem, idx) => {
|
||||||
templates[this.templateFilter[idx]] = _.isEmpty(resItem.listtemplatesresponse) ? { count: 0, template: [] } : resItem.listtemplatesresponse
|
templates[templateFilters[idx]] = _.isEmpty(resItem.listtemplatesresponse) ? { count: 0, template: [] } : resItem.listtemplatesresponse
|
||||||
this.templates = { ...templates }
|
this.options.templates = { ...templates }
|
||||||
})
|
})
|
||||||
}).catch((reason) => {
|
}).catch((reason) => {
|
||||||
console.log(reason)
|
console.log(reason)
|
||||||
@ -266,12 +358,18 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchTemplates (templateFilter, params) {
|
fetchTemplates (templateFilter, params) {
|
||||||
const args = Object.assign({}, params)
|
const args = Object.assign({}, params)
|
||||||
if (args.keyword || args.category !== templateFilter) {
|
if (this.isModernImageSelection && this.selectedGuestOsCategoryId && !['-1', '0'].includes(this.selectedGuestOsCategoryId)) {
|
||||||
|
args.oscategoryid = this.selectedGuestOsCategoryId
|
||||||
|
}
|
||||||
|
if (args.keyword || (args.category && args.category !== templateFilter)) {
|
||||||
args.page = 1
|
args.page = 1
|
||||||
args.pageSize = args.pageSize || 10
|
args.pageSize = args.pageSize || 10
|
||||||
}
|
}
|
||||||
args.zoneid = _.get(this.zone, 'id')
|
args.zoneid = this.resource.zoneid
|
||||||
args.templatefilter = templateFilter
|
args.templatefilter = templateFilter
|
||||||
|
if (this.resource.arch) {
|
||||||
|
args.arch = this.resource.arch
|
||||||
|
}
|
||||||
args.details = 'all'
|
args.details = 'all'
|
||||||
args.showicon = 'true'
|
args.showicon = 'true'
|
||||||
|
|
||||||
@ -285,17 +383,24 @@ export default {
|
|||||||
},
|
},
|
||||||
fetchDiskOfferings (params) {
|
fetchDiskOfferings (params) {
|
||||||
api('listDiskOfferings', { zoneid: this.resource.zoneid, listall: true, ...params }).then((response) => {
|
api('listDiskOfferings', { zoneid: this.resource.zoneid, listall: true, ...params }).then((response) => {
|
||||||
this.diskOfferings = response?.listdiskofferingsresponse?.diskoffering || []
|
this.options.diskOfferings = response?.listdiskofferingsresponse?.diskoffering || []
|
||||||
this.diskOfferingCount = response?.listdiskofferingsresponse?.count || 0
|
this.count.diskOfferings = response?.listdiskofferingsresponse?.count || 0
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
onSelectGuestOsCategory (value) {
|
||||||
|
this.selectedGuestOsCategoryId = value
|
||||||
|
this.fetchAllTemplates(this.imageSearchFilters)
|
||||||
|
},
|
||||||
onSelectDiskSize (rowSelected) {
|
onSelectDiskSize (rowSelected) {
|
||||||
this.diskOffering = rowSelected
|
this.diskOffering = rowSelected
|
||||||
this.dataPrefill.diskofferingid = rowSelected.id
|
this.dataPreFill.diskofferingid = rowSelected.id
|
||||||
},
|
},
|
||||||
updateFieldValue (input, value) {
|
updateFieldValue (input, value) {
|
||||||
this[input] = value
|
this[input] = value
|
||||||
this.dataPrefill[input] = value
|
this.dataPreFill[input] = value
|
||||||
|
},
|
||||||
|
filterOption (input, option) {
|
||||||
|
return option.label.toUpperCase().indexOf(input.toUpperCase()) >= 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,13 +26,13 @@
|
|||||||
v-ctrl-enter="handleSubmit"
|
v-ctrl-enter="handleSubmit"
|
||||||
@finish="handleSubmit">
|
@finish="handleSubmit">
|
||||||
<div v-if="template && template.userdataid">
|
<div v-if="template && template.userdataid">
|
||||||
<a-text type="primary">
|
<a-typography-text>
|
||||||
The template "{{ $t(this.template.name) }}" is linked to Userdata "{{ $t(this.template.userdataname) }}" with override policy "{{ $t(this.template.userdatapolicy) }}"
|
The template "{{ $t(this.template.name) }}" is linked to Userdata "{{ $t(this.template.userdataname) }}" with override policy "{{ $t(this.template.userdatapolicy) }}"
|
||||||
</a-text><br/><br/>
|
</a-typography-text><br/><br/>
|
||||||
<div v-if="templateUserDataParams.length > 0 && !doUserdataOverride">
|
<div v-if="templateUserDataParams.length > 0 && !doUserdataOverride">
|
||||||
<a-text type="primary" v-if="this.template && this.template.userdataid && templateUserDataParams.length > 0">
|
<a-typography-text v-if="this.template && this.template.userdataid && templateUserDataParams.length > 0">
|
||||||
Enter the values for the variables in userdata
|
Enter the values for the variables in userdata
|
||||||
</a-text>
|
</a-typography-text>
|
||||||
<a-input-group>
|
<a-input-group>
|
||||||
<a-table
|
<a-table
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@ -179,6 +179,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
emits: ['update-network-config', 'select-default-network-item', 'handler-error'],
|
||||||
methods: {
|
methods: {
|
||||||
initForm () {
|
initForm () {
|
||||||
this.formRef = ref()
|
this.formRef = ref()
|
||||||
|
|||||||
208
ui/src/views/compute/wizard/OsBasedImageRadioGroup.vue
Normal file
208
ui/src/views/compute/wizard/OsBasedImageRadioGroup.vue
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-list
|
||||||
|
class="form-item-scroll"
|
||||||
|
itemLayout="vertical"
|
||||||
|
size="small"
|
||||||
|
:dataSource="imagesList"
|
||||||
|
:pagination="false">
|
||||||
|
<template #renderItem="{ item, index }">
|
||||||
|
<a-list-item :key="item.id" @click="onClickRow(item)">
|
||||||
|
<a-radio-group
|
||||||
|
class="radio-group"
|
||||||
|
:key="index"
|
||||||
|
v-model:value="value"
|
||||||
|
@change="($event) => updateSelectionTemplateIso($event.target.value)">
|
||||||
|
<a-radio
|
||||||
|
class="radio-group__radio"
|
||||||
|
:value="item.id">
|
||||||
|
<resource-icon
|
||||||
|
v-if="item.icon && item.icon.base64image"
|
||||||
|
class="radio-group__os-logo"
|
||||||
|
:image="item.icon.base64image"
|
||||||
|
size="2x" />
|
||||||
|
<os-logo
|
||||||
|
v-else
|
||||||
|
class="radio-group__os-logo"
|
||||||
|
size="2x"
|
||||||
|
:osId="item.ostypeid"
|
||||||
|
:os-name="item.osName" />
|
||||||
|
|
||||||
|
{{ item.displaytext }}
|
||||||
|
<span v-if="item?.projectid">
|
||||||
|
| <project-outlined /> {{ item.project }}
|
||||||
|
</span>
|
||||||
|
<a-tooltip :title="$t('label.passwordenabled')" v-if="item.passwordenabled">
|
||||||
|
<lock-outlined style="margin-left: 8px;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip :title="$t('label.userdata')" v-if="item.userdataid">
|
||||||
|
<solution-outlined style="margin-left: 8px;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip :title="$t('label.isdynamicallyscalable')" v-if="item.isdynamicallyscalable">
|
||||||
|
<arrows-alt-outlined style="margin-left: 8px;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip :title="$t('label.isextractable')" v-if="item.isextractable">
|
||||||
|
<file-zip-outlined style="margin-left: 8px;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tag v-if="item.isfeatured" style="margin-left: 8px;">
|
||||||
|
{{ $t('label.isfeatured') }}
|
||||||
|
</a-tag>
|
||||||
|
<a-tag v-if="item.ispublic" style="margin-left: 8px;">
|
||||||
|
{{ $t('label.ispublic') }}
|
||||||
|
</a-tag>
|
||||||
|
<a-tag v-if="item.directdownload" style="margin-left: 8px;">
|
||||||
|
{{ $t('label.directdownload') }}
|
||||||
|
</a-tag>
|
||||||
|
<a-tag v-if="item.requireshvm" style="margin-left: 8px;">
|
||||||
|
{{ $t('label.requireshvm') }}
|
||||||
|
</a-tag>
|
||||||
|
</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
|
||||||
|
<div style="display: block; text-align: right;">
|
||||||
|
<a-pagination
|
||||||
|
size="small"
|
||||||
|
:current="options.page"
|
||||||
|
:pageSize="options.pageSize"
|
||||||
|
:total="itemCount"
|
||||||
|
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
|
||||||
|
:pageSizeOptions="['10', '20', '40', '80', '100', '200']"
|
||||||
|
@change="onChangePage"
|
||||||
|
@showSizeChange="onChangePageSize"
|
||||||
|
showSizeChanger>
|
||||||
|
<template #buildOptionText="props">
|
||||||
|
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||||
|
</template>
|
||||||
|
</a-pagination>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import OsLogo from '@/components/widgets/OsLogo'
|
||||||
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'OsBasedImageRadioGroup',
|
||||||
|
components: {
|
||||||
|
OsLogo,
|
||||||
|
ResourceIcon
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
imagesList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
inputDecorator: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
itemCount: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
preFillContent: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
value: '',
|
||||||
|
image: '',
|
||||||
|
options: {
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.onSelectTemplateIso()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selected (newVal, oldVal) {
|
||||||
|
if (newVal === oldVal) return
|
||||||
|
this.onSelectTemplateIso()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['emit-update-image', 'handle-search-filter'],
|
||||||
|
methods: {
|
||||||
|
onSelectTemplateIso () {
|
||||||
|
if (this.inputDecorator === 'templateid') {
|
||||||
|
this.value = this.preFillContent?.templateid ? this.preFillContent.templateid : this.selected
|
||||||
|
} else {
|
||||||
|
this.value = this.preFillContent?.isoid ? this.preFillContent.isoid : this.selected
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('emit-update-image', this.inputDecorator, this.value)
|
||||||
|
},
|
||||||
|
updateSelectionTemplateIso (id) {
|
||||||
|
this.$emit('emit-update-image', this.inputDecorator, id)
|
||||||
|
},
|
||||||
|
onChangePage (page, pageSize) {
|
||||||
|
this.options.page = page
|
||||||
|
this.options.pageSize = pageSize
|
||||||
|
this.$emit('handle-search-filter', this.options)
|
||||||
|
},
|
||||||
|
onChangePageSize (page, pageSize) {
|
||||||
|
this.options.page = page
|
||||||
|
this.options.pageSize = pageSize
|
||||||
|
this.$emit('handle-search-filter', this.options)
|
||||||
|
},
|
||||||
|
onClickRow (os) {
|
||||||
|
this.value = os.id
|
||||||
|
this.$emit('emit-update-image', this.inputDecorator, this.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.radio-group {
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
|
||||||
|
:deep(.ant-radio) {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__os-logo {
|
||||||
|
margin-top: -4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-spin-container) {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
margin-top: 20px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-list-split) .ant-list-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
373
ui/src/views/compute/wizard/OsBasedImageSelection.vue
Normal file
373
ui/src/views/compute/wizard/OsBasedImageSelection.vue
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-form-item v-if="imageTypeSelectionAllowed" :label="$t('label.type')" name="imagetype" ref="imagetype">
|
||||||
|
<a-radio-group
|
||||||
|
v-model:value="localSelectedImageType"
|
||||||
|
button-style="solid"
|
||||||
|
:disabled="imagePreSelected"
|
||||||
|
@change="emitChangeImageType()">
|
||||||
|
<a-radio-button value="templateid">{{ $t('label.template') }}</a-radio-button>
|
||||||
|
<a-radio-button value="isoid">{{ $t('label.iso') }}</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
<div style="margin-top: 5px; margin-bottom: 5px;">
|
||||||
|
{{ $t('message.' + localSelectedImageType.replace('id', '') + '.desc') }}
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('label.os')"
|
||||||
|
name="guestoscategoryid"
|
||||||
|
ref="guestoscategoryid"
|
||||||
|
v-if="!guestOsCategoriesSelectionDisallowed">
|
||||||
|
<block-radio-group-select
|
||||||
|
:maxBlocks="16"
|
||||||
|
:items="guestOsCategories"
|
||||||
|
:selectedValue="localSelectedGuestOsCategoryId"
|
||||||
|
:horizontalGutter="6"
|
||||||
|
:verticalGutter="6"
|
||||||
|
blockSize="square"
|
||||||
|
@change="handleGuestOsCategoryChange">
|
||||||
|
<template #radio-option="{ item }">
|
||||||
|
<div class="radio-option">
|
||||||
|
<div class="radio-opion__icon">
|
||||||
|
<resource-icon v-if="item.icon && item.icon.base64image" :image="item.icon.base64image" size="os" style="margin-bottom: 2px; margin-left: 1px" />
|
||||||
|
<font-awesome-icon v-else-if="['-1', '0'].includes(item.id)" :icon="['fas', item.id === '0' ? 'user' : 'images']" size="2x" :style="categoryFontAwesomeIconStyle" />
|
||||||
|
<os-logo v-else size="2x" :os-name="item.name" />
|
||||||
|
</div>
|
||||||
|
<a-tooltip placement="top" :title="item.name">
|
||||||
|
<div class="ellipsis">{{ item.name }}</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #select-option="{ item }">
|
||||||
|
<span>
|
||||||
|
<resource-icon v-if="item.icon && item.icon.base64image" :image="item.icon.base64image" size="2x" style="margin-right: 5px"/>
|
||||||
|
<font-awesome-icon
|
||||||
|
v-else-if="item.id === '0'"
|
||||||
|
:icon="['fas', 'user']"
|
||||||
|
size="2x"
|
||||||
|
:style="[$store.getters.darkMode ? { color: 'rgba(255, 255, 255, 0.65)' } : { color: '#666' }]"
|
||||||
|
/>
|
||||||
|
<os-logo v-else :os-name="item.name" style="margin-right: 5px" />
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</block-radio-group-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-card>
|
||||||
|
<os-based-image-selection-search-view
|
||||||
|
v-if="!imagePreSelected"
|
||||||
|
class="search-input"
|
||||||
|
:filtersDisabled="searchFiltersDisabled"
|
||||||
|
@search="handleImageSearch">
|
||||||
|
</os-based-image-selection-search-view>
|
||||||
|
<a-spin :spinning="imagesLoading">
|
||||||
|
<os-based-image-radio-group
|
||||||
|
:imagesList="imagesList"
|
||||||
|
:itemCount="imagesCount"
|
||||||
|
:input-decorator="localSelectedImageType"
|
||||||
|
:selected="selectedImageId"
|
||||||
|
:preFillContent="preFillContent"
|
||||||
|
@emit-update-image="updateImage"
|
||||||
|
@handle-search-filter="($event) => eventPagination($event)"
|
||||||
|
/>
|
||||||
|
</a-spin>
|
||||||
|
<div v-if="diskSizeSelectionAllowed">
|
||||||
|
<div>
|
||||||
|
{{ $t('label.override.rootdisk.size') }}
|
||||||
|
<a-switch
|
||||||
|
v-model:checked="localRootDiskOverrideChecked"
|
||||||
|
:disabled="rootDiskOverrideDisabled"
|
||||||
|
@change="handleRootDiskOverrideCheckedChange"
|
||||||
|
style="margin-left: 10px;"/>
|
||||||
|
<div v-if="diskSizeSelectionDeployAsIsMessageVisible"> {{ $t('message.deployasis') }} </div>
|
||||||
|
</div>
|
||||||
|
<disk-size-selection
|
||||||
|
v-if="showRootDiskSizeChanger"
|
||||||
|
:input-decorator="diskSizeSelectionInputDecorator"
|
||||||
|
:preFillContent="preFillContent"
|
||||||
|
:isCustomized="true"
|
||||||
|
:minDiskSize="preFillContent.minrootdisksize"
|
||||||
|
@update-disk-size="emitUpdateDiskSize"
|
||||||
|
style="margin-top: 10px;"/>
|
||||||
|
</div>
|
||||||
|
<a-form-item :label="$t('label.hypervisor')" v-if="localSelectedImageType === 'isoid'">
|
||||||
|
<a-select
|
||||||
|
v-model:value="localSelectedIsoHypervisor"
|
||||||
|
:preFillContent="preFillContent"
|
||||||
|
:options="isoHypervisorItems"
|
||||||
|
@change="handleIsoHypervisorChange()"
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
:filterOption="filterOption" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BlockRadioGroupSelect from '@/components/widgets/BlockRadioGroupSelect.vue'
|
||||||
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
|
import OsLogo from '@/components/widgets/OsLogo'
|
||||||
|
import OsBasedImageSelectionSearchView from '@views/compute/wizard/OsBasedImageSelectionSearchView'
|
||||||
|
import OsBasedImageRadioGroup from '@views/compute/wizard/OsBasedImageRadioGroup'
|
||||||
|
import DiskSizeSelection from '@views/compute/wizard/DiskSizeSelection'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'OsBasedImageSelection',
|
||||||
|
components: {
|
||||||
|
BlockRadioGroupSelect,
|
||||||
|
ResourceIcon,
|
||||||
|
OsLogo,
|
||||||
|
OsBasedImageSelectionSearchView,
|
||||||
|
OsBasedImageRadioGroup,
|
||||||
|
DiskSizeSelection
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
imageTypeSelectionAllowed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
selectedImageType: {
|
||||||
|
type: String,
|
||||||
|
default: 'templateid'
|
||||||
|
},
|
||||||
|
imagePreSelected: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
guestOsCategoriesSelectionDisallowed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
guestOsCategories: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
guestOsCategoriesLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
selectedGuestOsCategoryId: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
imageItems: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
imagesLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
diskSizeSelectionAllowed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
diskSizeSelectionDeployAsIsMessageVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
diskSizeSelectionInputDecorator: {
|
||||||
|
type: String,
|
||||||
|
default: 'rootdisksize'
|
||||||
|
},
|
||||||
|
rootDiskOverrideDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
rootDiskOverrideChecked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
isoHypervisorItems: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
selectedIsoHypervisor: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
filterOption: {
|
||||||
|
type: Function,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
preFillContent: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
filterType: 'executable',
|
||||||
|
selectedImageId: '',
|
||||||
|
imageSearchFilters: {},
|
||||||
|
showRootDiskSizeChanger: false,
|
||||||
|
// Local data properties to mirror props
|
||||||
|
localSelectedImageType: this.selectedImageType,
|
||||||
|
localSelectedGuestOsCategoryId: this.selectedGuestOsCategoryId,
|
||||||
|
localRootDiskOverrideChecked: this.rootDiskOverrideChecked,
|
||||||
|
localSelectedIsoHypervisor: this.selectedIsoHypervisor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.filterType = this.defaultImageFilter
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedImageType (newValue) {
|
||||||
|
this.localSelectedImageType = newValue
|
||||||
|
},
|
||||||
|
guestOsCategories (newValue) {
|
||||||
|
this.imageSearchFilters = {}
|
||||||
|
},
|
||||||
|
selectedGuestOsCategoryId (newValue) {
|
||||||
|
this.localSelectedGuestOsCategoryId = newValue
|
||||||
|
this.updateImageFilterType()
|
||||||
|
},
|
||||||
|
rootDiskOverrideChecked (newValue) {
|
||||||
|
this.localRootDiskOverrideChecked = newValue
|
||||||
|
},
|
||||||
|
selectedIsoHypervisor (newValue) {
|
||||||
|
this.localSelectedIsoHypervisor = newValue
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
defaultImageFilter () {
|
||||||
|
return ['DomainAdmin', 'User'].includes(this.$store.getters.userInfo.roletype) ? 'executable' : 'all'
|
||||||
|
},
|
||||||
|
imagesList () {
|
||||||
|
if (!this.localSelectedImageType || !this.imageItems || !this.imageItems[this.filterType]) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const imageTypeKey = this.localSelectedImageType.slice(0, -2)
|
||||||
|
return this.imageItems[this.filterType][imageTypeKey] || []
|
||||||
|
},
|
||||||
|
imagesCount () {
|
||||||
|
return this.imageItems[this.filterType] ? this.imageItems[this.filterType].count || 0 : 0
|
||||||
|
},
|
||||||
|
selectedCategory () {
|
||||||
|
if (this.localSelectedGuestOsCategoryId && this.guestOsCategories) {
|
||||||
|
return this.guestOsCategories.find(option => option.id === this.localSelectedGuestOsCategoryId)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
categoryFontAwesomeIconStyle () {
|
||||||
|
return [this.$store.getters.darkMode ? { color: 'rgba(255, 255, 255, 0.65)' } : { color: '#666' }]
|
||||||
|
},
|
||||||
|
searchFiltersDisabled () {
|
||||||
|
return this.selectedCategory?.disableimagefilters
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['change-image-type', 'change-guest-os-category', 'update-image', 'handle-image-search-filter', 'change-root-disk-override-checked', 'update-disk-size', 'change-iso-hypervisor'],
|
||||||
|
methods: {
|
||||||
|
emitChangeImageType () {
|
||||||
|
this.$emit('change-image-type', this.localSelectedImageType)
|
||||||
|
},
|
||||||
|
handleGuestOsCategoryChange (value) {
|
||||||
|
this.localSelectedGuestOsCategoryId = value
|
||||||
|
this.$emit('change-guest-os-category', this.localSelectedGuestOsCategoryId)
|
||||||
|
},
|
||||||
|
updateImage (decorator, id) {
|
||||||
|
this.selectedImageId = id
|
||||||
|
this.$emit('update-image', decorator, id)
|
||||||
|
},
|
||||||
|
handleImageSearch (searchFilters) {
|
||||||
|
this.imageSearchFilters = {
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10
|
||||||
|
}
|
||||||
|
Object.assign(this.imageSearchFilters, searchFilters)
|
||||||
|
this.updateImageFilterType()
|
||||||
|
this.emitSearchFilter()
|
||||||
|
},
|
||||||
|
updateImageFilterType () {
|
||||||
|
this.filterType = this.defaultImageFilter
|
||||||
|
if (this.localSelectedGuestOsCategoryId === '0') {
|
||||||
|
this.filterType = 'self'
|
||||||
|
} else {
|
||||||
|
if (this.imageSearchFilters?.featured) {
|
||||||
|
this.filterType = 'featured'
|
||||||
|
} else if (this.imageSearchFilters?.public) {
|
||||||
|
this.filterType = 'community'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
eventPagination (pagination) {
|
||||||
|
Object.assign(this.imageSearchFilters, pagination)
|
||||||
|
this.emitSearchFilter()
|
||||||
|
},
|
||||||
|
emitSearchFilter () {
|
||||||
|
this.$emit('handle-image-search-filter', this.imageSearchFilters)
|
||||||
|
},
|
||||||
|
changeFilterType (value) {
|
||||||
|
this.filterType = value
|
||||||
|
},
|
||||||
|
handleRootDiskOverrideCheckedChange (value) {
|
||||||
|
this.showRootDiskSizeChanger = value
|
||||||
|
this.$emit('change-root-disk-override-checked', value)
|
||||||
|
},
|
||||||
|
emitUpdateDiskSize (decorator, value) {
|
||||||
|
this.$emit('update-disk-size', decorator, value)
|
||||||
|
},
|
||||||
|
handleIsoHypervisorChange () {
|
||||||
|
this.$emit('change-iso-hypervisor', this.localIsoHypervisor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.search-input {
|
||||||
|
z-index: 8;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs-nav-scroll) {
|
||||||
|
min-height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-option {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ellipsis {
|
||||||
|
max-width: 80px;
|
||||||
|
flex-grow: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-opion__icon {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
119
ui/src/views/compute/wizard/OsBasedImageSelectionSearchView.vue
Normal file
119
ui/src/views/compute/wizard/OsBasedImageSelectionSearchView.vue
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span class="filter-group">
|
||||||
|
<a-row type="flex">
|
||||||
|
<a-col flex="200px" v-if="!filtersDisabled">
|
||||||
|
<a-select
|
||||||
|
mode="multiple"
|
||||||
|
class="filter-select"
|
||||||
|
:placeholder="$t('label.filterby')"
|
||||||
|
v-model:value="filterValues"
|
||||||
|
@change="handleFilterChange"
|
||||||
|
showSearch
|
||||||
|
allowClear
|
||||||
|
:showArrow="true"
|
||||||
|
optionFilterProp="label"
|
||||||
|
:filterOption="(input, option) => {
|
||||||
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
}">
|
||||||
|
<template #suffixIcon><filter-outlined class="ant-select-suffix" /></template>
|
||||||
|
<a-select-option
|
||||||
|
v-for="filter in filters"
|
||||||
|
:key="filter"
|
||||||
|
:label="$t('label.' + filter)">
|
||||||
|
{{ $t('label.' + filter) }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-col>
|
||||||
|
<a-col flex="auto">
|
||||||
|
<a-input-search
|
||||||
|
class="filter-search"
|
||||||
|
:placeholder="$t('label.search')"
|
||||||
|
v-model:value="searchedText"
|
||||||
|
allowClear
|
||||||
|
@search="handleTextSearch" />
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'OsBasedImageSelectionSearchView',
|
||||||
|
props: {
|
||||||
|
filtersDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
filters: [
|
||||||
|
'public',
|
||||||
|
'featured'
|
||||||
|
],
|
||||||
|
filterValues: undefined,
|
||||||
|
searchedText: null,
|
||||||
|
paramsFilter: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTextSearch (value) {
|
||||||
|
this.searchedText = value
|
||||||
|
if (value) {
|
||||||
|
this.paramsFilter.keyword = value
|
||||||
|
} else {
|
||||||
|
delete this.paramsFilter.keyword
|
||||||
|
}
|
||||||
|
const params = this.paramsFilter
|
||||||
|
if (this.filtersDisabled) {
|
||||||
|
delete this.paramsFilter.public
|
||||||
|
delete this.paramsFilter.featured
|
||||||
|
}
|
||||||
|
this.$emit('search', params)
|
||||||
|
},
|
||||||
|
handleFilterChange () {
|
||||||
|
this.paramsFilter = {}
|
||||||
|
if (Array.isArray(this.filterValues)) {
|
||||||
|
this.filterValues.forEach(e => {
|
||||||
|
this.paramsFilter[e] = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.searchedText) {
|
||||||
|
this.paramsFilter.keyword = this.searchedText
|
||||||
|
}
|
||||||
|
this.$emit('search', this.paramsFilter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.filter-group .ant-select,
|
||||||
|
.filter-group .ant-input-search {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-select {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
51
ui/src/views/compute/wizard/ZoneBlockRadioGroupSelect.vue
Normal file
51
ui/src/views/compute/wizard/ZoneBlockRadioGroupSelect.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<block-radio-group-select>
|
||||||
|
<template #radio-option="{ item }">
|
||||||
|
<span>
|
||||||
|
<resource-icon
|
||||||
|
v-if="item && item.icon && item.icon.base64image"
|
||||||
|
:image="item.icon.base64image"
|
||||||
|
size="2x" />
|
||||||
|
<global-outlined size="2x" v-else />
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #select-option="{ item }">
|
||||||
|
<span>
|
||||||
|
<resource-icon v-if="item.icon && zone1.icon.base64image" :image="item.icon.base64image" size="2x" style="margin-right: 5px"/>
|
||||||
|
<global-outlined v-else style="margin-right: 5px" />
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</block-radio-group-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BlockRadioGroupSelect from '@/components/widgets/BlockRadioGroupSelect.vue'
|
||||||
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ZoneBlockRadioGroupSelect',
|
||||||
|
components: {
|
||||||
|
BlockRadioGroupSelect,
|
||||||
|
ResourceIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -38,8 +38,8 @@
|
|||||||
:rowExpandable="(record) => record.downloaddetails.length > 0">
|
:rowExpandable="(record) => record.downloaddetails.length > 0">
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'zonename'">
|
<template v-if="column.key === 'zonename'">
|
||||||
<span v-if="fetchZoneIcon(record.zoneid)">
|
<span v-if="record.zoneicon && record.zoneicon.base64image">
|
||||||
<resource-icon :image="zoneIcon" size="1x" style="margin-right: 5px"/>
|
<resource-icon :image="record.zoneicon.base64image" size="2x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<global-outlined v-else style="margin-right: 5px" />
|
<global-outlined v-else style="margin-right: 5px" />
|
||||||
<span> {{ record.zonename }} </span>
|
<span> {{ record.zonename }} </span>
|
||||||
@ -52,30 +52,39 @@
|
|||||||
<span v-if="record.created">{{ $toLocaleDate(record.created) }}</span>
|
<span v-if="record.created">{{ $toLocaleDate(record.created) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'actions'">
|
<template v-if="column.key === 'actions'">
|
||||||
<span style="margin-right: 5px">
|
<span style="margin-right: 5px" v-if="'deployVirtualMachine' in $store.getters.apis">
|
||||||
<tooltip-button
|
<tooltip-button
|
||||||
:tooltip="$t('label.action.copy.iso')"
|
:disabled="!record.isready"
|
||||||
:disabled="!('copyIso' in $store.getters.apis && record.isready)"
|
:title="$t('label.vm.add')"
|
||||||
icon="copy-outlined"
|
icon="rocket-outlined"
|
||||||
:loading="copyLoading"
|
@onClick="onAddInstance(record)"/>
|
||||||
@click="showCopyIso(record)" />
|
|
||||||
</span>
|
</span>
|
||||||
<span style="margin-right: 5px">
|
<span v-if="isActionsOnIsoPermitted">
|
||||||
<a-popconfirm
|
<span style="margin-right: 5px">
|
||||||
v-if="'deleteIso' in $store.getters.apis"
|
|
||||||
placement="topRight"
|
|
||||||
:title="$t('message.action.delete.iso')"
|
|
||||||
:ok-text="$t('label.yes')"
|
|
||||||
:cancel-text="$t('label.no')"
|
|
||||||
:loading="deleteLoading"
|
|
||||||
@confirm="deleteIso(record)"
|
|
||||||
>
|
|
||||||
<tooltip-button
|
<tooltip-button
|
||||||
:tooltip="$t('label.action.delete.iso')"
|
:tooltip="$t('label.action.copy.iso')"
|
||||||
type="primary"
|
:disabled="!('copyIso' in $store.getters.apis && record.isready)"
|
||||||
:danger="true"
|
icon="copy-outlined"
|
||||||
icon="delete-outlined" />
|
:loading="copyLoading"
|
||||||
</a-popconfirm>
|
@click="showCopyIso(record)" />
|
||||||
|
</span>
|
||||||
|
<span style="margin-right: 5px">
|
||||||
|
<a-popconfirm
|
||||||
|
v-if="'deleteIso' in $store.getters.apis"
|
||||||
|
placement="topRight"
|
||||||
|
:title="$t('message.action.delete.iso')"
|
||||||
|
:ok-text="$t('label.yes')"
|
||||||
|
:cancel-text="$t('label.no')"
|
||||||
|
:loading="deleteLoading"
|
||||||
|
@confirm="deleteIso(record)"
|
||||||
|
>
|
||||||
|
<tooltip-button
|
||||||
|
:tooltip="$t('label.action.delete.iso')"
|
||||||
|
type="primary"
|
||||||
|
:danger="true"
|
||||||
|
icon="delete-outlined" />
|
||||||
|
</a-popconfirm>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@ -162,7 +171,7 @@
|
|||||||
}"
|
}"
|
||||||
:loading="zoneLoading"
|
:loading="zoneLoading"
|
||||||
v-focus="true">
|
v-focus="true">
|
||||||
<a-select-option v-for="zone in zones" :key="zone.id" :label="zone.name">
|
<a-select-option v-for="zone in copyZones" :key="zone.id" :label="zone.name">
|
||||||
<div>
|
<div>
|
||||||
<span v-if="zone.icon && zone.icon.base64image">
|
<span v-if="zone.icon && zone.icon.base64image">
|
||||||
<resource-icon :image="zone.icon.base64image" size="1x" style="margin-right: 5px"/>
|
<resource-icon :image="zone.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||||
@ -237,6 +246,7 @@ export default {
|
|||||||
showCopyActionForm: false,
|
showCopyActionForm: false,
|
||||||
currentRecord: {},
|
currentRecord: {},
|
||||||
zones: [],
|
zones: [],
|
||||||
|
copyZones: [],
|
||||||
zoneLoading: false,
|
zoneLoading: false,
|
||||||
copyLoading: false,
|
copyLoading: false,
|
||||||
deleteLoading: false,
|
deleteLoading: false,
|
||||||
@ -278,6 +288,13 @@ export default {
|
|||||||
key: 'isready',
|
key: 'isready',
|
||||||
title: this.$t('label.isready'),
|
title: this.$t('label.isready'),
|
||||||
dataIndex: 'isready'
|
dataIndex: 'isready'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'actions',
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'actions',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 130
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
this.storagePoolInnerColumns = [
|
this.storagePoolInnerColumns = [
|
||||||
@ -308,15 +325,6 @@ export default {
|
|||||||
dataIndex: 'downloadState'
|
dataIndex: 'downloadState'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
if (this.isActionPermitted()) {
|
|
||||||
this.columns.push({
|
|
||||||
key: 'actions',
|
|
||||||
title: '',
|
|
||||||
dataIndex: 'actions',
|
|
||||||
fixed: 'right',
|
|
||||||
width: 100
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const userInfo = this.$store.getters.userInfo
|
const userInfo = this.$store.getters.userInfo
|
||||||
if (!['Admin'].includes(userInfo.roletype) &&
|
if (!['Admin'].includes(userInfo.roletype) &&
|
||||||
@ -332,6 +340,16 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
isActionsOnIsoPermitted () {
|
||||||
|
return (['Admin'].includes(this.$store.getters.userInfo.roletype) || // If admin or owner or belongs to current project
|
||||||
|
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account) ||
|
||||||
|
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.projectid && this.$store.getters.project && this.$store.getters.project.id && this.resource.projectid === this.$store.getters.project.id)) &&
|
||||||
|
(this.resource.isready || !this.resource.status || this.resource.status.indexOf('Downloaded') === -1) && // Iso is ready or downloaded
|
||||||
|
this.resource.account !== 'system'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update-zones'],
|
||||||
methods: {
|
methods: {
|
||||||
initForm () {
|
initForm () {
|
||||||
this.formRef = ref()
|
this.formRef = ref()
|
||||||
@ -358,16 +376,10 @@ export default {
|
|||||||
this.$notifyError(error)
|
this.$notifyError(error)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.fetchLoading = false
|
this.fetchLoading = false
|
||||||
|
this.updateImageZones()
|
||||||
})
|
})
|
||||||
this.fetchZoneData()
|
this.fetchZoneData()
|
||||||
},
|
this.fetchOsCategoryId()
|
||||||
fetchZoneIcon (zoneid) {
|
|
||||||
const zoneItem = this.zones.filter(zone => zone.id === zoneid)
|
|
||||||
if (zoneItem?.[0]?.icon?.base64image) {
|
|
||||||
this.zoneIcon = zoneItem[0].icon.base64image
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
handleChangePage (page, pageSize) {
|
handleChangePage (page, pageSize) {
|
||||||
this.page = page
|
this.page = page
|
||||||
@ -379,13 +391,6 @@ export default {
|
|||||||
this.pageSize = pageSize
|
this.pageSize = pageSize
|
||||||
this.fetchData()
|
this.fetchData()
|
||||||
},
|
},
|
||||||
isActionPermitted () {
|
|
||||||
return (['Admin'].includes(this.$store.getters.userInfo.roletype) || // If admin or owner or belongs to current project
|
|
||||||
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account) ||
|
|
||||||
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.projectid && this.$store.getters.project && this.$store.getters.project.id && this.resource.projectid === this.$store.getters.project.id)) &&
|
|
||||||
(this.resource.isready || !this.resource.status || this.resource.status.indexOf('Downloaded') === -1) && // Iso is ready or downloaded
|
|
||||||
this.resource.account !== 'system'
|
|
||||||
},
|
|
||||||
setSelection (selection) {
|
setSelection (selection) {
|
||||||
this.selectedRowKeys = selection
|
this.selectedRowKeys = selection
|
||||||
this.$emit('selection-change', this.selectedRowKeys)
|
this.$emit('selection-change', this.selectedRowKeys)
|
||||||
@ -501,9 +506,41 @@ export default {
|
|||||||
this.zoneLoading = true
|
this.zoneLoading = true
|
||||||
api('listZones', { showicon: true }).then(json => {
|
api('listZones', { showicon: true }).then(json => {
|
||||||
const zones = json.listzonesresponse.zone || []
|
const zones = json.listzonesresponse.zone || []
|
||||||
this.zones = [...zones.filter((zone) => this.currentRecord.zoneid !== zone.id)]
|
this.zones = zones
|
||||||
|
this.copyZones = [...zones.filter((zone) => this.currentRecord.zoneid !== zone.id)]
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.zoneLoading = false
|
this.zoneLoading = false
|
||||||
|
this.updateImageZones()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateImageZones () {
|
||||||
|
if (!Array.isArray(this.dataSource) || !Array.isArray(this.zones) ||
|
||||||
|
this.dataSource.length === 0 || this.zones.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const imageZones = []
|
||||||
|
this.dataSource.forEach(item => {
|
||||||
|
const zone = this.zones.find(zone => item.zoneid === zone.id)
|
||||||
|
if (zone && zone.icon) {
|
||||||
|
item.zoneicon = zone.icon
|
||||||
|
}
|
||||||
|
imageZones.push(zone)
|
||||||
|
})
|
||||||
|
if (imageZones.length !== 0) {
|
||||||
|
this.$emit('update-zones', imageZones)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchOsCategoryId () {
|
||||||
|
const needed = this.$route.meta.name === 'iso' &&
|
||||||
|
'listOsTypes' in this.$store.getters.apis &&
|
||||||
|
this.resource && this.resource.ostypeid &&
|
||||||
|
(this.$config.imageSelectionInterface === undefined ||
|
||||||
|
this.$config.imageSelectionInterface === 'modern')
|
||||||
|
if (!needed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
api('listOsTypes', { id: this.resource.ostypeid }).then(json => {
|
||||||
|
this.osCategoryId = json?.listostypesresponse?.ostype?.[0]?.oscategoryid || null
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
showCopyIso (record) {
|
showCopyIso (record) {
|
||||||
@ -558,6 +595,19 @@ export default {
|
|||||||
},
|
},
|
||||||
closeModal () {
|
closeModal () {
|
||||||
this.showConfirmationAction = false
|
this.showConfirmationAction = false
|
||||||
|
},
|
||||||
|
onAddInstance (record) {
|
||||||
|
const query = { isoid: this.resource.id, zoneid: record.zoneid }
|
||||||
|
if (this.resource.arch) {
|
||||||
|
query.arch = this.resource.arch
|
||||||
|
}
|
||||||
|
if (this.osCategoryId) {
|
||||||
|
query.oscategoryid = this.osCategoryId
|
||||||
|
}
|
||||||
|
this.$router.push({
|
||||||
|
path: '/action/deployVirtualMachine',
|
||||||
|
query: query
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -582,7 +582,7 @@ export default {
|
|||||||
this.fetchCustomHypervisorName()
|
this.fetchCustomHypervisorName()
|
||||||
this.fetchZone()
|
this.fetchZone()
|
||||||
this.fetchOsTypes()
|
this.fetchOsTypes()
|
||||||
this.fetchTemplateTypes()
|
this.templateTypes.opts = this.$fetchTemplateTypes()
|
||||||
this.architectureTypes.opts = this.$fetchCpuArchitectureTypes()
|
this.architectureTypes.opts = this.$fetchCpuArchitectureTypes()
|
||||||
this.fetchUserData()
|
this.fetchUserData()
|
||||||
this.fetchUserdataPolicy()
|
this.fetchUserdataPolicy()
|
||||||
@ -726,33 +726,6 @@ export default {
|
|||||||
this.osTypes.loading = false
|
this.osTypes.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fetchTemplateTypes () {
|
|
||||||
this.templateTypes.opts = []
|
|
||||||
const templatetypes = []
|
|
||||||
templatetypes.push({
|
|
||||||
id: 'USER',
|
|
||||||
description: 'USER'
|
|
||||||
})
|
|
||||||
templatetypes.push({
|
|
||||||
id: 'VNF',
|
|
||||||
description: 'VNF'
|
|
||||||
})
|
|
||||||
if (this.isAdminRole) {
|
|
||||||
templatetypes.push({
|
|
||||||
id: 'SYSTEM',
|
|
||||||
description: 'SYSTEM'
|
|
||||||
})
|
|
||||||
templatetypes.push({
|
|
||||||
id: 'BUILTIN',
|
|
||||||
description: 'BUILTIN'
|
|
||||||
})
|
|
||||||
templatetypes.push({
|
|
||||||
id: 'ROUTING',
|
|
||||||
description: 'ROUTING'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.templateTypes.opts = templatetypes
|
|
||||||
},
|
|
||||||
fetchUserData () {
|
fetchUserData () {
|
||||||
const params = {}
|
const params = {}
|
||||||
params.listAll = true
|
params.listAll = true
|
||||||
|
|||||||
@ -38,8 +38,8 @@
|
|||||||
:rowExpandable="(record) => record.downloaddetails.length > 0">
|
:rowExpandable="(record) => record.downloaddetails.length > 0">
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'zonename'">
|
<template v-if="column.key === 'zonename'">
|
||||||
<span v-if="fetchZoneIcon(record.zoneid)">
|
<span v-if="record.zoneicon && record.zoneicon.base64image">
|
||||||
<resource-icon :image="zoneIcon" size="2x" style="margin-right: 5px"/>
|
<resource-icon :image="record.zoneicon.base64image" size="2x" style="margin-right: 5px"/>
|
||||||
</span>
|
</span>
|
||||||
<global-outlined v-else style="margin-right: 5px" />
|
<global-outlined v-else style="margin-right: 5px" />
|
||||||
<span> {{ record.zonename }} </span>
|
<span> {{ record.zonename }} </span>
|
||||||
@ -52,21 +52,32 @@
|
|||||||
<span v-if="record.created">{{ $toLocaleDate(record.created) }}</span>
|
<span v-if="record.created">{{ $toLocaleDate(record.created) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'actions'">
|
<template v-if="column.key === 'actions'">
|
||||||
<tooltip-button
|
<span style="margin-right: 5px" v-if="'deployVirtualMachine' in $store.getters.apis">
|
||||||
style="margin-right: 5px"
|
<tooltip-button
|
||||||
:disabled="!('copyTemplate' in $store.getters.apis && record.isready)"
|
:disabled="!record.isready"
|
||||||
:title="$t('label.action.copy.template')"
|
:title="$t('label.vm.add')"
|
||||||
icon="copy-outlined"
|
icon="rocket-outlined"
|
||||||
:loading="copyLoading"
|
@onClick="onAddInstance(record)"/>
|
||||||
@onClick="showCopyTemplate(record)" />
|
</span>
|
||||||
<tooltip-button
|
<span v-if="isActionsOnTemplatePermitted">
|
||||||
style="margin-right: 5px"
|
<span style="margin-right: 5px">
|
||||||
:disabled="!('deleteTemplate' in $store.getters.apis)"
|
<tooltip-button
|
||||||
:title="$t('label.action.delete.template')"
|
:disabled="!('copyTemplate' in $store.getters.apis && record.isready)"
|
||||||
type="primary"
|
:title="$t('label.action.copy.template')"
|
||||||
:danger="true"
|
icon="copy-outlined"
|
||||||
icon="delete-outlined"
|
:loading="copyLoading"
|
||||||
@onClick="onShowDeleteModal(record)"/>
|
@onClick="showCopyTemplate(record)" />
|
||||||
|
</span>
|
||||||
|
<span style="margin-right: 5px">
|
||||||
|
<tooltip-button
|
||||||
|
:disabled="!('deleteTemplate' in $store.getters.apis)"
|
||||||
|
:title="$t('label.action.delete.template')"
|
||||||
|
type="primary"
|
||||||
|
:danger="true"
|
||||||
|
icon="delete-outlined"
|
||||||
|
@onClick="onShowDeleteModal(record)"/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<template #expandedRowRender="{ record }">
|
<template #expandedRowRender="{ record }">
|
||||||
@ -168,7 +179,7 @@
|
|||||||
}"
|
}"
|
||||||
:loading="zoneLoading"
|
:loading="zoneLoading"
|
||||||
v-focus="true">
|
v-focus="true">
|
||||||
<a-select-option v-for="zone in zones" :key="zone.id" :label="zone.name">
|
<a-select-option v-for="zone in copyZones" :key="zone.id" :label="zone.name">
|
||||||
<div>
|
<div>
|
||||||
<span v-if="zone.icon && zone.icon.base64image">
|
<span v-if="zone.icon && zone.icon.base64image">
|
||||||
<resource-icon :image="zone.icon.base64image" size="2x" style="margin-right: 5px"/>
|
<resource-icon :image="zone.icon.base64image" size="2x" style="margin-right: 5px"/>
|
||||||
@ -282,6 +293,7 @@ export default {
|
|||||||
showCopyActionForm: false,
|
showCopyActionForm: false,
|
||||||
currentRecord: {},
|
currentRecord: {},
|
||||||
zones: [],
|
zones: [],
|
||||||
|
copyZones: [],
|
||||||
zoneLoading: false,
|
zoneLoading: false,
|
||||||
copyLoading: false,
|
copyLoading: false,
|
||||||
deleteLoading: false,
|
deleteLoading: false,
|
||||||
@ -298,7 +310,8 @@ export default {
|
|||||||
confirmMessage: this.$t('label.confirm.delete.templates')
|
confirmMessage: this.$t('label.confirm.delete.templates')
|
||||||
},
|
},
|
||||||
modalWidth: '30vw',
|
modalWidth: '30vw',
|
||||||
showTable: false
|
showTable: false,
|
||||||
|
osCategoryId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate () {
|
beforeCreate () {
|
||||||
@ -324,6 +337,12 @@ export default {
|
|||||||
key: 'isready',
|
key: 'isready',
|
||||||
title: this.$t('label.isready'),
|
title: this.$t('label.isready'),
|
||||||
dataIndex: 'isready'
|
dataIndex: 'isready'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'actions',
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'actions',
|
||||||
|
width: 130
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
this.imageStoreInnerColumns = [
|
this.imageStoreInnerColumns = [
|
||||||
@ -354,14 +373,6 @@ export default {
|
|||||||
dataIndex: 'downloadState'
|
dataIndex: 'downloadState'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
if (this.isActionPermitted()) {
|
|
||||||
this.columns.push({
|
|
||||||
key: 'actions',
|
|
||||||
title: '',
|
|
||||||
dataIndex: 'actions',
|
|
||||||
width: 100
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const userInfo = this.$store.getters.userInfo
|
const userInfo = this.$store.getters.userInfo
|
||||||
if (!['Admin'].includes(userInfo.roletype) &&
|
if (!['Admin'].includes(userInfo.roletype) &&
|
||||||
@ -378,6 +389,16 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
isActionsOnTemplatePermitted () {
|
||||||
|
return (['Admin'].includes(this.$store.getters.userInfo.roletype) || // If admin or owner or belongs to current project
|
||||||
|
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account) ||
|
||||||
|
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.projectid && this.$store.getters.project && this.$store.getters.project.id && this.resource.projectid === this.$store.getters.project.id)) &&
|
||||||
|
(this.resource.isready || !this.resource.status || this.resource.status.indexOf('Downloaded') === -1) && // Template is ready or downloaded
|
||||||
|
this.resource.templatetype !== 'SYSTEM'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update-zones'],
|
||||||
methods: {
|
methods: {
|
||||||
initForm () {
|
initForm () {
|
||||||
this.formRef = ref()
|
this.formRef = ref()
|
||||||
@ -404,16 +425,10 @@ export default {
|
|||||||
this.$notifyError(error)
|
this.$notifyError(error)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.fetchLoading = false
|
this.fetchLoading = false
|
||||||
|
this.updateImageZones()
|
||||||
})
|
})
|
||||||
this.fetchZoneData()
|
this.fetchZoneData()
|
||||||
},
|
this.fetchOsCategoryId()
|
||||||
fetchZoneIcon (zoneid) {
|
|
||||||
const zoneItem = this.zones.filter(zone => zone.id === zoneid)
|
|
||||||
if (zoneItem?.[0]?.icon?.base64image) {
|
|
||||||
this.zoneIcon = zoneItem[0].icon.base64image
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
handleChangePage (page, pageSize) {
|
handleChangePage (page, pageSize) {
|
||||||
this.page = page
|
this.page = page
|
||||||
@ -425,13 +440,6 @@ export default {
|
|||||||
this.pageSize = pageSize
|
this.pageSize = pageSize
|
||||||
this.fetchData()
|
this.fetchData()
|
||||||
},
|
},
|
||||||
isActionPermitted () {
|
|
||||||
return (['Admin'].includes(this.$store.getters.userInfo.roletype) || // If admin or owner or belongs to current project
|
|
||||||
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account) ||
|
|
||||||
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.projectid && this.$store.getters.project && this.$store.getters.project.id && this.resource.projectid === this.$store.getters.project.id)) &&
|
|
||||||
(this.resource.isready || !this.resource.status || this.resource.status.indexOf('Downloaded') === -1) && // Template is ready or downloaded
|
|
||||||
this.resource.templatetype !== 'SYSTEM'
|
|
||||||
},
|
|
||||||
setSelection (selection) {
|
setSelection (selection) {
|
||||||
this.selectedRowKeys = selection
|
this.selectedRowKeys = selection
|
||||||
if (selection?.length > 0) {
|
if (selection?.length > 0) {
|
||||||
@ -566,9 +574,41 @@ export default {
|
|||||||
this.zoneLoading = true
|
this.zoneLoading = true
|
||||||
api('listZones', { showicon: true }).then(json => {
|
api('listZones', { showicon: true }).then(json => {
|
||||||
const zones = json.listzonesresponse.zone || []
|
const zones = json.listzonesresponse.zone || []
|
||||||
this.zones = [...zones.filter((zone) => this.currentRecord.zoneid !== zone.id)]
|
this.zones = zones
|
||||||
|
this.copyZones = [...zones.filter((zone) => this.currentRecord.zoneid !== zone.id)]
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.zoneLoading = false
|
this.zoneLoading = false
|
||||||
|
this.updateImageZones()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateImageZones () {
|
||||||
|
if (!Array.isArray(this.dataSource) || !Array.isArray(this.zones) ||
|
||||||
|
this.dataSource.length === 0 || this.zones.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const imageZones = []
|
||||||
|
this.dataSource.forEach(item => {
|
||||||
|
const zone = this.zones.find(zone => item.zoneid === zone.id)
|
||||||
|
if (zone && zone.icon) {
|
||||||
|
item.zoneicon = zone.icon
|
||||||
|
}
|
||||||
|
imageZones.push(zone)
|
||||||
|
})
|
||||||
|
if (imageZones.length !== 0) {
|
||||||
|
this.$emit('update-zones', imageZones)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchOsCategoryId () {
|
||||||
|
const needed = this.$route.meta.name === 'template' &&
|
||||||
|
'listOsTypes' in this.$store.getters.apis &&
|
||||||
|
this.resource && this.resource.ostypeid &&
|
||||||
|
(this.$config.imageSelectionInterface === undefined ||
|
||||||
|
this.$config.imageSelectionInterface === 'modern')
|
||||||
|
if (!needed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
api('listOsTypes', { id: this.resource.ostypeid }).then(json => {
|
||||||
|
this.osCategoryId = json?.listostypesresponse?.ostype?.[0]?.oscategoryid || null
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
showCopyTemplate (record) {
|
showCopyTemplate (record) {
|
||||||
@ -634,6 +674,19 @@ export default {
|
|||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.formRef.value.scrollToField(error.errorFields[0].name)
|
this.formRef.value.scrollToField(error.errorFields[0].name)
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
onAddInstance (record) {
|
||||||
|
const query = { templateid: this.resource.id, zoneid: record.zoneid }
|
||||||
|
if (this.resource.arch) {
|
||||||
|
query.arch = this.resource.arch
|
||||||
|
}
|
||||||
|
if (this.osCategoryId) {
|
||||||
|
query.oscategoryid = this.osCategoryId
|
||||||
|
}
|
||||||
|
this.$router.push({
|
||||||
|
path: '/action/deployVirtualMachine',
|
||||||
|
query: query
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
package com.cloud.utils.db;
|
package com.cloud.utils.db;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,6 +47,8 @@ public interface EntityManager {
|
|||||||
*/
|
*/
|
||||||
public <T> T findByUuid(Class<T> entityType, String uuid);
|
public <T> T findByUuid(Class<T> entityType, String uuid);
|
||||||
|
|
||||||
|
<T> List<T> listByUuids(Class<T> entityType, Collection<String> uuids);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a unique entity by uuid string, including those removed entries
|
* Finds a unique entity by uuid string, including those removed entries
|
||||||
* @param <T> entity class
|
* @param <T> entity class
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user