Merge branch 'main' of https://github.com/apache/cloudstack into clvm-enhancements

This commit is contained in:
Pearl Dsilva 2026-03-17 07:12:21 -04:00
commit 798401ec39
214 changed files with 18758 additions and 2955 deletions

View File

@ -146,6 +146,7 @@ jobs:
smoke/test_vm_snapshot_kvm
smoke/test_vm_snapshots
smoke/test_volumes
smoke/test_vpc_conserve_mode
smoke/test_vpc_ipv6
smoke/test_vpc_redundant
smoke/test_vpc_router_nics

View File

@ -24,15 +24,18 @@ import com.cloud.network.Network;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.command.admin.config.ResetCfgCmd;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
import org.apache.cloudstack.api.command.admin.network.CloneNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd;
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6PrefixCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd;
import org.apache.cloudstack.api.command.admin.network.NetworkOfferingBaseCmd;
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.offering.CloneDiskOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.CloneServiceOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
@ -105,6 +108,33 @@ public interface ConfigurationService {
*/
ServiceOffering createServiceOffering(CreateServiceOfferingCmd cmd);
/**
* Clones a service offering with optional parameter overrides
*
* @param cmd
* the command object that specifies the source offering ID and optional parameter overrides
* @return the newly created service offering cloned from source, null otherwise
*/
ServiceOffering cloneServiceOffering(CloneServiceOfferingCmd cmd);
/**
* Clones a disk offering with optional parameter overrides
*
* @param cmd
* the command object that specifies the source offering ID and optional parameter overrides
* @return the newly created disk offering cloned from source, null otherwise
*/
DiskOffering cloneDiskOffering(CloneDiskOfferingCmd cmd);
/**
* Clones a network offering with optional parameter overrides
*
* @param cmd
* the command object that specifies the source offering ID and optional parameter overrides
* @return the newly created network offering cloned from source, null otherwise
*/
NetworkOffering cloneNetworkOffering(CloneNetworkOfferingCmd cmd);
/**
* Updates a service offering
*
@ -282,7 +312,7 @@ public interface ConfigurationService {
boolean releasePublicIpRange(ReleasePublicIpRangeCmd cmd);
NetworkOffering createNetworkOffering(CreateNetworkOfferingCmd cmd);
NetworkOffering createNetworkOffering(NetworkOfferingBaseCmd cmd);
NetworkOffering updateNetworkOffering(UpdateNetworkOfferingCmd cmd);

View File

@ -298,8 +298,9 @@ public class EventTypes {
public static final String EVENT_REGISTER_CNI_CONFIG = "REGISTER.CNI.CONFIG";
public static final String EVENT_DELETE_CNI_CONFIG = "DELETE.CNI.CONFIG";
//register for user API and secret keys
//user API and secret keys
public static final String EVENT_REGISTER_FOR_SECRET_API_KEY = "REGISTER.USER.KEY";
public static final String EVENT_DELETE_SECRET_API_KEY = "DELETE.USER.KEY";
public static final String API_KEY_ACCESS_UPDATE = "API.KEY.ACCESS.UPDATE";
// Template Events
@ -374,11 +375,13 @@ public class EventTypes {
// Service Offerings
public static final String EVENT_SERVICE_OFFERING_CREATE = "SERVICE.OFFERING.CREATE";
public static final String EVENT_SERVICE_OFFERING_CLONE = "SERVICE.OFFERING.CLONE";
public static final String EVENT_SERVICE_OFFERING_EDIT = "SERVICE.OFFERING.EDIT";
public static final String EVENT_SERVICE_OFFERING_DELETE = "SERVICE.OFFERING.DELETE";
// Disk Offerings
public static final String EVENT_DISK_OFFERING_CREATE = "DISK.OFFERING.CREATE";
public static final String EVENT_DISK_OFFERING_CLONE = "DISK.OFFERING.CLONE";
public static final String EVENT_DISK_OFFERING_EDIT = "DISK.OFFERING.EDIT";
public static final String EVENT_DISK_OFFERING_DELETE = "DISK.OFFERING.DELETE";
@ -399,6 +402,7 @@ public class EventTypes {
// Network offerings
public static final String EVENT_NETWORK_OFFERING_CREATE = "NETWORK.OFFERING.CREATE";
public static final String EVENT_NETWORK_OFFERING_CLONE = "NETWORK.OFFERING.CLONE";
public static final String EVENT_NETWORK_OFFERING_ASSIGN = "NETWORK.OFFERING.ASSIGN";
public static final String EVENT_NETWORK_OFFERING_EDIT = "NETWORK.OFFERING.EDIT";
public static final String EVENT_NETWORK_OFFERING_REMOVE = "NETWORK.OFFERING.REMOVE";
@ -598,6 +602,7 @@ public class EventTypes {
// VPC offerings
public static final String EVENT_VPC_OFFERING_CREATE = "VPC.OFFERING.CREATE";
public static final String EVENT_VPC_OFFERING_CLONE = "VPC.OFFERING.CLONE";
public static final String EVENT_VPC_OFFERING_UPDATE = "VPC.OFFERING.UPDATE";
public static final String EVENT_VPC_OFFERING_DELETE = "VPC.OFFERING.DELETE";
@ -630,6 +635,7 @@ public class EventTypes {
// Backup and Recovery events
public static final String EVENT_VM_BACKUP_IMPORT_OFFERING = "BACKUP.IMPORT.OFFERING";
public static final String EVENT_VM_BACKUP_OFFERING_CLONE = "BACKUP.OFFERING.CLONE";
public static final String EVENT_VM_BACKUP_OFFERING_ASSIGN = "BACKUP.OFFERING.ASSIGN";
public static final String EVENT_VM_BACKUP_OFFERING_REMOVE = "BACKUP.OFFERING.REMOVE";
public static final String EVENT_VM_BACKUP_CREATE = "BACKUP.CREATE";
@ -1045,11 +1051,13 @@ public class EventTypes {
// Service Offerings
entityEventDetails.put(EVENT_SERVICE_OFFERING_CREATE, ServiceOffering.class);
entityEventDetails.put(EVENT_SERVICE_OFFERING_CLONE, ServiceOffering.class);
entityEventDetails.put(EVENT_SERVICE_OFFERING_EDIT, ServiceOffering.class);
entityEventDetails.put(EVENT_SERVICE_OFFERING_DELETE, ServiceOffering.class);
// Disk Offerings
entityEventDetails.put(EVENT_DISK_OFFERING_CREATE, DiskOffering.class);
entityEventDetails.put(EVENT_DISK_OFFERING_CLONE, DiskOffering.class);
entityEventDetails.put(EVENT_DISK_OFFERING_EDIT, DiskOffering.class);
entityEventDetails.put(EVENT_DISK_OFFERING_DELETE, DiskOffering.class);
@ -1070,6 +1078,7 @@ public class EventTypes {
// Network offerings
entityEventDetails.put(EVENT_NETWORK_OFFERING_CREATE, NetworkOffering.class);
entityEventDetails.put(EVENT_NETWORK_OFFERING_CLONE, NetworkOffering.class);
entityEventDetails.put(EVENT_NETWORK_OFFERING_ASSIGN, NetworkOffering.class);
entityEventDetails.put(EVENT_NETWORK_OFFERING_EDIT, NetworkOffering.class);
entityEventDetails.put(EVENT_NETWORK_OFFERING_REMOVE, NetworkOffering.class);

View File

@ -98,7 +98,7 @@ public interface KubernetesCluster extends ControlledEntity, com.cloud.utils.fsm
s_fsm.addTransition(State.Running, Event.ScaleDownRequested, State.Scaling);
s_fsm.addTransition(State.Stopped, Event.ScaleUpRequested, State.ScalingStoppedCluster);
s_fsm.addTransition(State.Scaling, Event.OperationSucceeded, State.Running);
s_fsm.addTransition(State.Scaling, Event.OperationFailed, State.Alert);
s_fsm.addTransition(State.Scaling, Event.OperationFailed, State.Running);
s_fsm.addTransition(State.ScalingStoppedCluster, Event.OperationSucceeded, State.Stopped);
s_fsm.addTransition(State.ScalingStoppedCluster, Event.OperationFailed, State.Alert);

View File

@ -18,6 +18,7 @@ package com.cloud.kubernetes.cluster;
import org.apache.cloudstack.acl.ControlledEntity;
import java.util.List;
import java.util.Map;
import com.cloud.user.Account;
@ -33,8 +34,10 @@ public interface KubernetesServiceHelper extends Adapter {
ControlledEntity findByUuid(String uuid);
ControlledEntity findByVmId(long vmId);
void checkVmCanBeDestroyed(UserVm userVm);
void checkVmAffinityGroupsCanBeUpdated(UserVm userVm);
boolean isValidNodeType(String nodeType);
Map<String, Long> getServiceOfferingNodeTypeMap(Map<String, Map<String, String>> serviceOfferingNodeTypeMap);
Map<String, Long> getTemplateNodeTypeMap(Map<String, Map<String, String>> templateNodeTypeMap);
Map<String, List<Long>> getAffinityGroupNodeTypeMap(Map<String, Map<String, String>> affinityGroupNodeTypeMap);
void cleanupForAccount(Account account);
}

View File

@ -279,4 +279,6 @@ public interface NetworkService {
IpAddresses getIpAddressesFromIps(String ipAddress, String ip6Address, String macAddress);
String getNicVlanValueForExternalVm(NicTO nic);
Long getPreferredNetworkIdForPublicIpRuleAssignment(IpAddress ip, Long networkId);
}

View File

@ -108,7 +108,7 @@ public interface LoadBalancingRulesService {
/**
* Assign a virtual machine or list of virtual machines, or Map of <vmId vmIp> to a load balancer.
*/
boolean assignToLoadBalancer(long lbRuleId, List<Long> vmIds, Map<Long, List<String>> vmIdIpMap, boolean isAutoScaleVM);
boolean assignToLoadBalancer(long lbRuleId, List<Long> vmIds, Map<Long, List<String>> vmIdIpMap, Map<Long, Long> vmIdNetworkMap, boolean isAutoScaleVM);
boolean assignSSLCertToLoadBalancerRule(Long lbRuleId, String certName, String publicCert, String privateKey);

View File

@ -84,4 +84,6 @@ public interface VpcOffering extends InternalIdentity, Identity {
NetworkOffering.RoutingMode getRoutingMode();
Boolean isSpecifyAsNumber();
boolean isConserveMode();
}

View File

@ -20,6 +20,7 @@ package com.cloud.network.vpc;
import java.util.List;
import java.util.Map;
import org.apache.cloudstack.api.command.admin.vpc.CloneVPCOfferingCmd;
import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd;
import org.apache.cloudstack.api.command.admin.vpc.UpdateVPCOfferingCmd;
import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd;
@ -34,12 +35,14 @@ public interface VpcProvisioningService {
VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd);
VpcOffering cloneVPCOffering(CloneVPCOfferingCmd cmd);
VpcOffering createVpcOffering(String name, String displayText, List<String> supportedServices,
Map<String, List<String>> serviceProviders,
Map serviceCapabilitystList, NetUtils.InternetProtocol internetProtocol,
Long serviceOfferingId, String externalProvider, NetworkOffering.NetworkMode networkMode,
List<Long> domainIds, List<Long> zoneIds, VpcOffering.State state,
NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber);
NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode);
Pair<List<? extends VpcOffering>,Integer> listVpcOfferings(ListVPCOfferingsCmd cmd);

View File

@ -21,12 +21,13 @@ import java.util.Map;
import com.cloud.utils.Pair;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.RolePermissionEntity;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPair;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.command.admin.account.CreateAccountCmd;
import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd;
import org.apache.cloudstack.api.command.admin.user.RegisterUserKeyCmd;
import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
import com.cloud.dc.DataCenter;
import com.cloud.domain.Domain;
@ -35,6 +36,14 @@ import com.cloud.network.vpc.VpcOffering;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import org.apache.cloudstack.api.command.admin.user.DeleteUserKeysCmd;
import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd;
import org.apache.cloudstack.api.command.admin.user.ListUserKeyRulesCmd;
import org.apache.cloudstack.api.command.admin.user.ListUserKeysCmd;
import org.apache.cloudstack.api.command.admin.user.RegisterUserKeysCmd;
import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
import org.apache.cloudstack.api.response.ApiKeyPairResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
import org.apache.cloudstack.backup.BackupOffering;
@ -97,7 +106,7 @@ public interface AccountService {
void markUserRegistered(long userId);
public String[] createApiKeyAndSecretKey(RegisterUserKeyCmd cmd);
ApiKeyPair createApiKeyAndSecretKey(RegisterUserKeysCmd cmd);
public String[] createApiKeyAndSecretKey(final long userId);
@ -125,6 +134,8 @@ public interface AccountService {
void validateAccountHasAccessToResource(Account account, AccessType accessType, Object resource);
void validateCallingUserHasAccessToDesiredUser(Long userId);
Long finalizeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly);
/**
@ -134,9 +145,15 @@ public interface AccountService {
*/
UserAccount getUserAccountById(Long userId);
public Pair<Boolean, Map<String, String>> getKeys(GetUserKeysCmd cmd);
Pair<Boolean, Map<String, String>> getKeys(GetUserKeysCmd cmd);
public Pair<Boolean, Map<String, String>> getKeys(Long userId);
ListResponse<ApiKeyPairResponse> listKeys(ListUserKeysCmd cmd);
List<ApiKeyPairPermission> listKeyRules(ListUserKeyRulesCmd cmd);
void deleteApiKey(DeleteUserKeysCmd cmd);
void deleteApiKey(ApiKeyPair id);
/**
* Lists user two-factor authentication provider plugins
@ -151,4 +168,13 @@ public interface AccountService {
*/
UserTwoFactorAuthenticator getUserTwoFactorAuthenticationProvider(final Long domainId);
ApiKeyPair getLatestUserKeyPair(Long userId);
ApiKeyPair getKeyPairById(Long id);
ApiKeyPair getKeyPairByApiKey(String apiKey);
String getAccessingApiKey(BaseCmd cmd);
List<RolePermissionEntity> getAllKeypairPermissions(String apiKey);
}

View File

@ -0,0 +1,21 @@
// 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 com.cloud.user;
public enum ApiKeyPairState {
ENABLED, REMOVED, EXPIRED
}

View File

@ -65,14 +65,6 @@ public interface User extends OwnedBy, InternalIdentity {
public void setState(Account.State state);
public String getApiKey();
public void setApiKey(String apiKey);
public String getSecretKey();
public void setSecretKey(String secretKey);
public String getTimezone();
public void setTimezone(String timezone);

View File

@ -39,10 +39,6 @@ public interface UserAccount extends InternalIdentity {
String getState();
String getApiKey();
String getSecretKey();
Date getCreated();
Date getRemoved();

View File

@ -96,6 +96,7 @@ public interface VmDetailConstants {
String CKS_NODE_TYPE = "node";
String OFFERING = "offering";
String TEMPLATE = "template";
String AFFINITY_GROUP = "affinitygroup";
// VMware to KVM VM migrations specific
String VMWARE_TO_KVM_PREFIX = "vmware-to-kvm";

View File

@ -20,6 +20,7 @@ import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.Account;
import com.cloud.user.User;
import com.cloud.utils.component.Adapter;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import java.util.List;
@ -31,8 +32,8 @@ public interface APIChecker extends Adapter {
// If true, apiChecker has checked the operation
// If false, apiChecker is unable to handle the operation or not implemented
// On exception, checkAccess failed don't allow
boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException;
boolean checkAccess(Account account, String apiCommandName) throws PermissionDeniedException;
boolean checkAccess(User user, String apiCommandName, ApiKeyPairPermission... apiKeyPairPermissions) throws PermissionDeniedException;
boolean checkAccess(Account account, String apiCommandName, ApiKeyPairPermission... apiKeyPairPermissions) throws PermissionDeniedException;
/**
* Verifies if the account has permission for the given list of APIs and returns only the allowed ones.
*
@ -43,4 +44,5 @@ public interface APIChecker extends Adapter {
*/
List<String> getApisAllowedToUser(Role role, User user, List<String> apiNames) throws PermissionDeniedException;
boolean isEnabled();
List<RolePermissionEntity> getImplicitRolePermissions(RoleType roleType);
}

View File

@ -21,7 +21,7 @@ import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface RolePermissionEntity extends InternalIdentity, Identity {
public enum Permission {
enum Permission {
ALLOW, DENY
}
Rule getRule();

View File

@ -104,5 +104,26 @@ public interface RoleService {
List<RolePermission> findAllPermissionsBy(Long roleId);
List<RolePermissionEntity> findAllRolePermissionsEntityBy(Long roleId, boolean considerImplicitRules);
Permission getRolePermission(String permission);
int removeRolesIfNeeded(List<? extends Role> roles);
/**
* Checks if the role of the caller account has compatible permissions of the specified role permissions.
* For each permission of the {@param rolePermissionsToAccess}, the role of the caller needs to contain the same permission.
*
* @param rolePermissions the permissions of the caller role.
* @param rolePermissionsToAccess the permissions for the role that the caller role wants to access.
* @return True if the role can be accessed with the given permissions; false otherwise.
*/
boolean roleHasPermission(Map<String, RolePermissionEntity> rolePermissions, List<RolePermissionEntity> rolePermissionsToAccess);
/**
* Given a list of role permissions, returns a {@link Map} containing the API name as the key and the {@link RolePermissionEntity} for the API as the value.
*
* @param rolePermissions Permissions for the role from role.
*/
Map<String, RolePermissionEntity> getRoleRulesAndPermissions(List<RolePermissionEntity> rolePermissions);
}

View File

@ -25,16 +25,18 @@ import org.apache.commons.lang3.StringUtils;
public final class Rule {
private final String rule;
private final Pattern matchingPattern;
private final static Pattern ALLOWED_PATTERN = Pattern.compile("^[a-zA-Z0-9*]+$");
public Rule(final String rule) {
validate(rule);
this.rule = rule;
matchingPattern = Pattern.compile(rule.toLowerCase().replace("*", "(\\w*\\*?)+"));
}
public boolean matches(final String commandName) {
return StringUtils.isNotEmpty(commandName)
&& commandName.toLowerCase().matches(rule.toLowerCase().replace("*", "\\w*"));
return StringUtils.isNotEmpty(commandName) &&
matchingPattern.matcher(commandName.toLowerCase()).matches();
}
public String getRuleString() {

View File

@ -0,0 +1,38 @@
// 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.acl.apikeypair;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
import java.util.Date;
public interface ApiKeyPair extends ControlledEntity, InternalIdentity, Identity {
Long getUserId();
Date getStartDate();
Date getEndDate();
Date getCreated();
String getDescription();
String getApiKey();
String getSecretKey();
String getName();
Date getRemoved();
void setRemoved(Date date);
void validateDate();
boolean hasEndDatePassed();
}

View File

@ -0,0 +1,23 @@
// 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.acl.apikeypair;
import org.apache.cloudstack.acl.RolePermissionEntity;
public interface ApiKeyPairPermission extends RolePermissionEntity {
long getApiKeyPairId();
}

View File

@ -0,0 +1,27 @@
// 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.acl.apikeypair;
import java.util.List;
public interface ApiKeyPairService {
List<ApiKeyPairPermission> findAllPermissionsByKeyPairId(Long apiKeyPairId, Long roleId);
ApiKeyPair findByApiKey(String apiKey);
ApiKeyPair findById(Long id);
}

View File

@ -66,5 +66,4 @@ public interface AffinityGroupService {
boolean isAffinityGroupAvailableInDomain(long affinityGroupId, long domainId);
}

View File

@ -29,6 +29,9 @@ import java.util.List;
public class AffinityProcessorBase extends AdapterBase implements AffinityGroupProcessor {
public static final String AFFINITY_TYPE_HOST = "host affinity";
public static final String AFFINITY_TYPE_HOST_ANTI = "host anti-affinity";
protected String _type;
@Override

View File

@ -19,6 +19,7 @@ package org.apache.cloudstack.api;
public class ApiConstants {
public static final String ACCOUNT = "account";
public static final String ACCOUNTS = "accounts";
public static final String ACCOUNT_NAME = "accountname";
public static final String ACCOUNT_TYPE = "accounttype";
public static final String ACCOUNT_ID = "accountid";
public static final String ACCOUNT_IDS = "accountids";
@ -46,6 +47,7 @@ public class ApiConstants {
public static final String AS_NUMBER_ID = "asnumberid";
public static final String ASN_RANGE = "asnrange";
public static final String ASN_RANGE_ID = "asnrangeid";
public static final String API_KEY_FILTER = "apikeyfilter";
public static final String ASYNC_BACKUP = "asyncbackup";
public static final String AUTO_SELECT = "autoselect";
public static final String USER_API_KEY = "userapikey";
@ -356,6 +358,7 @@ public class ApiConstants {
public static final String JOB_STATUS = "jobstatus";
public static final String KEEPALIVE_ENABLED = "keepaliveenabled";
public static final String KERNEL_VERSION = "kernelversion";
public static final String KEYPAIR_ID = "keypairid";
public static final String KEY = "key";
public static final String LABEL = "label";
public static final String LASTNAME = "lastname";
@ -521,9 +524,9 @@ public class ApiConstants {
public static final String SCHEDULE = "schedule";
public static final String SCHEDULE_ID = "scheduleid";
public static final String SCOPE = "scope";
public static final String USER_SECRET_KEY = "usersecretkey";
public static final String SEARCH_BASE = "searchbase";
public static final String SECONDARY_IP = "secondaryip";
public static final String SECRET_KEY = "secretkey";
public static final String SECURITY_GROUP_IDS = "securitygroupids";
public static final String SECURITY_GROUP_NAMES = "securitygroupnames";
public static final String SECURITY_GROUP_NAME = "securitygroupname";
@ -540,6 +543,7 @@ public class ApiConstants {
public static final String SHOW_RESOURCE_ICON = "showicon";
public static final String SHOW_INACTIVE = "showinactive";
public static final String SHOW_UNIQUE = "showunique";
public static final String SHOW_PERMISSIONS = "showpermissions";
public static final String SIGNATURE = "signature";
public static final String SIGNATURE_VERSION = "signatureversion";
public static final String SINCE = "since";
@ -555,6 +559,7 @@ public class ApiConstants {
public static final String USE_STORAGE_REPLICATION = "usestoragereplication";
public static final String SOURCE_CIDR_LIST = "sourcecidrlist";
public static final String SOURCE_OFFERING_ID = "sourceofferingid";
public static final String SOURCE_ZONE_ID = "sourcezoneid";
public static final String SSL_VERIFICATION = "sslverification";
public static final String START_ASN = "startasn";
@ -623,7 +628,6 @@ public class ApiConstants {
public static final String USERNAME = "username";
public static final String USER_CONFIGURABLE = "userconfigurable";
public static final String USER_SECURITY_GROUP_LIST = "usersecuritygrouplist";
public static final String USER_SECRET_KEY = "usersecretkey";
public static final String USE_VIRTUAL_NETWORK = "usevirtualnetwork";
public static final String USE_VIRTUAL_ROUTER_IP_RESOLVER = "userouteripresolver";
public static final String UPDATE_IN_SEQUENCE = "updateinsequence";
@ -765,6 +769,7 @@ public class ApiConstants {
public static final String ROLE_TYPE = "roletype";
public static final String ROLE_NAME = "rolename";
public static final String PERMISSION = "permission";
public static final String PERMISSIONS = "permissions";
public static final String RULE = "rule";
public static final String RULES = "rules";
public static final String RULE_ID = "ruleid";
@ -982,6 +987,7 @@ public class ApiConstants {
public static final String REGION_ID = "regionid";
public static final String VPC_OFF_ID = "vpcofferingid";
public static final String VPC_OFF_NAME = "vpcofferingname";
public static final String VPC_OFFERING_CONSERVE_MODE = "vpcofferingconservemode";
public static final String NETWORK = "network";
public static final String VPC_ID = "vpcid";
public static final String VPC_NAME = "vpcname";
@ -1028,7 +1034,7 @@ public class ApiConstants {
public static final String NSX_PROVIDER_PORT = "nsxproviderport";
public static final String NSX_CONTROLLER_ID = "nsxcontrollerid";
public static final String S3_ACCESS_KEY = "accesskey";
public static final String S3_SECRET_KEY = "secretkey";
public static final String SECRET_KEY = "secretkey";
public static final String S3_END_POINT = "endpoint";
public static final String S3_BUCKET_NAME = "bucket";
public static final String S3_SIGNER = "s3signer";
@ -1240,6 +1246,13 @@ public class ApiConstants {
public static final String MAX_SIZE = "maxsize";
public static final String NODE_TYPE_OFFERING_MAP = "nodeofferings";
public static final String NODE_TYPE_TEMPLATE_MAP = "nodetemplates";
public static final String NODE_TYPE_AFFINITY_GROUP_MAP = "nodeaffinitygroups";
public static final String CONTROL_AFFINITY_GROUP_IDS = "controlaffinitygroupids";
public static final String CONTROL_AFFINITY_GROUP_NAMES = "controlaffinitygroupnames";
public static final String WORKER_AFFINITY_GROUP_IDS = "workeraffinitygroupids";
public static final String WORKER_AFFINITY_GROUP_NAMES = "workeraffinitygroupnames";
public static final String ETCD_AFFINITY_GROUP_IDS = "etcdaffinitygroupids";
public static final String ETCD_AFFINITY_GROUP_NAMES = "etcdaffinitygroupnames";
public static final String BOOT_TYPE = "boottype";
public static final String BOOT_MODE = "bootmode";

View File

@ -49,5 +49,7 @@ public interface ApiServerService {
boolean resetPassword(UserAccount userAccount, String token, String password);
String getDomainId(Map<String, Object[]> params);
boolean isPostRequestsAndTimestampsEnforced();
}

View File

@ -29,6 +29,7 @@ public abstract class BaseAsyncCmd extends BaseCmd {
public static final String migrationSyncObject = "migration";
public static final String snapshotHostSyncObject = "snapshothost";
public static final String gslbSyncObject = "globalserverloadbalancer";
public static final String user = "user";
private Object job;

View File

@ -36,6 +36,7 @@ import com.cloud.bgp.BGPService;
import org.apache.cloudstack.acl.ProjectRoleService;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairService;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.alert.AlertService;
import org.apache.cloudstack.annotation.AnnotationService;
@ -221,6 +222,8 @@ public abstract class BaseCmd {
@Inject
public Ipv6Service ipv6Service;
@Inject
public ApiKeyPairService apiKeyPairService;
@Inject
public VnfTemplateManager vnfTemplateManager;
@Inject
public BucketApiService _bucketService;

View File

@ -24,6 +24,8 @@ import java.util.Set;
import org.apache.cloudstack.api.response.ConsoleSessionResponse;
import org.apache.cloudstack.consoleproxy.ConsoleSession;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPair;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ApiConstants.HostDetails;
@ -41,6 +43,7 @@ import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.BackupRepositoryResponse;
import org.apache.cloudstack.api.response.BackupScheduleResponse;
import org.apache.cloudstack.api.response.BaseRolePermissionResponse;
import org.apache.cloudstack.api.response.BucketResponse;
import org.apache.cloudstack.api.response.CapacityResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
@ -77,6 +80,7 @@ import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse;
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.ApiKeyPairResponse;
import org.apache.cloudstack.api.response.LBHealthCheckResponse;
import org.apache.cloudstack.api.response.LBStickinessResponse;
import org.apache.cloudstack.api.response.ListResponse;
@ -583,4 +587,8 @@ public interface ResponseGenerator {
GuiThemeResponse createGuiThemeResponse(GuiThemeJoin guiThemeJoin);
ConsoleSessionResponse createConsoleSessionResponse(ConsoleSession consoleSession, ResponseView responseView);
ApiKeyPairResponse createKeyPairResponse(ApiKeyPair keyPair);
ListResponse<BaseRolePermissionResponse> createKeypairPermissionsResponse(List<ApiKeyPairPermission> permissions);
}

View File

@ -0,0 +1,166 @@
// 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.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.offering.DomainAndZoneIdResolver;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
import java.util.Arrays;
import java.util.List;
import java.util.function.LongFunction;
@APICommand(name = "cloneBackupOffering",
description = "Clones a backup offering from an existing offering",
responseObject = BackupOfferingResponse.class, since = "4.23.0",
authorized = {RoleType.Admin})
public class CloneBackupOfferingCmd extends BaseAsyncCmd implements DomainAndZoneIdResolver {
@Inject
protected BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
////////////////////////////////////////////////////
@Parameter(name = ApiConstants.SOURCE_OFFERING_ID, type = BaseCmd.CommandType.UUID, entityType = BackupOfferingResponse.class,
required = true, description = "The ID of the source backup offering to clone from")
private Long sourceOfferingId;
@Parameter(name = ApiConstants.NAME, type = BaseCmd.CommandType.STRING, required = true,
description = "The name of the cloned offering")
private String name;
@Parameter(name = ApiConstants.DESCRIPTION, type = BaseCmd.CommandType.STRING, required = false,
description = "The description of the cloned offering")
private String description;
@Parameter(name = ApiConstants.EXTERNAL_ID, type = BaseCmd.CommandType.STRING, required = false,
description = "The backup offering ID (from backup provider side)")
private String externalId;
@Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
description = "The zone ID", required = false)
private Long zoneId;
@Parameter(name = ApiConstants.DOMAIN_ID,
type = CommandType.STRING,
description = "the ID of the containing domain(s) as comma separated string, public for public offerings",
length = 4096)
private String domainIds;
@Parameter(name = ApiConstants.ALLOW_USER_DRIVEN_BACKUPS, type = BaseCmd.CommandType.BOOLEAN,
description = "Whether users are allowed to create adhoc backups and backup schedules", required = false)
private Boolean userDrivenBackups;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getSourceOfferingId() {
return sourceOfferingId;
}
public String getName() {
return name;
}
public String getExternalId() {
return externalId;
}
public Long getZoneId() {
return zoneId;
}
public String getDescription() {
return description;
}
public Boolean getUserDrivenBackups() {
return userDrivenBackups;
}
public List<Long> getDomainIds() {
if (domainIds != null && !domainIds.isEmpty()) {
return Arrays.asList(Arrays.stream(domainIds.split(",")).map(domainId -> Long.parseLong(domainId.trim())).toArray(Long[]::new));
}
LongFunction<List<Long>> defaultDomainsProvider = null;
if (backupManager != null) {
defaultDomainsProvider = backupManager::getBackupOfferingDomains;
}
return resolveDomainIds(domainIds, sourceOfferingId, defaultDomainsProvider, "backup offering");
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
BackupOffering policy = backupManager.cloneBackupOffering(this);
if (policy == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone backup offering");
}
BackupOfferingResponse response = _responseGenerator.createBackupOfferingResponse(policy);
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage());
} catch (CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_OFFERING_CLONE;
}
@Override
public String getEventDescription() {
return "Cloning backup offering: " + name + " from source offering: " + (sourceOfferingId == null ? "" : sourceOfferingId.toString());
}
}

View File

@ -54,7 +54,7 @@ import java.util.Set;
public class ImportBackupOfferingCmd extends BaseAsyncCmd {
@Inject
private BackupManager backupManager;
protected BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
@ -86,7 +86,8 @@ public class ImportBackupOfferingCmd extends BaseAsyncCmd {
type = CommandType.LIST,
collectionType = CommandType.UUID,
entityType = DomainResponse.class,
description = "the ID of the containing domain(s), null for public offerings")
description = "the ID of the containing domain(s), null for public offerings",
since = "4.23.0")
private List<Long> domainIds;
/////////////////////////////////////////////////////

View File

@ -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.network;
import java.util.List;
import org.apache.cloudstack.api.APICommand;
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.NetworkOfferingResponse;
import com.cloud.offering.NetworkOffering;
@APICommand(name = "cloneNetworkOffering",
description = "Clones a network offering. All parameters are copied from the source offering unless explicitly overridden. " +
"Use 'addServices' and 'dropServices' to modify the service list without respecifying everything.",
responseObject = NetworkOfferingResponse.class,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false,
since = "4.23.0")
public class CloneNetworkOfferingCmd extends NetworkOfferingBaseCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.SOURCE_OFFERING_ID,
type = BaseCmd.CommandType.UUID,
entityType = NetworkOfferingResponse.class,
required = true,
description = "The ID of the source network offering to clone from")
private Long sourceOfferingId;
@Parameter(name = "addservices",
type = CommandType.LIST,
collectionType = CommandType.STRING,
description = "Services to add to the cloned offering (in addition to source offering services). " +
"If specified along with 'supportedservices', this parameter is ignored.")
private List<String> addServices;
@Parameter(name = "dropservices",
type = CommandType.LIST,
collectionType = CommandType.STRING,
description = "Services to remove from the cloned offering (that exist in source offering). " +
"If specified along with 'supportedservices', this parameter is ignored.")
private List<String> dropServices;
@Parameter(name = ApiConstants.TRAFFIC_TYPE,
type = CommandType.STRING,
description = "The traffic type for the network offering. Supported type in current release is GUEST only")
private String traffictype;
@Parameter(name = ApiConstants.GUEST_IP_TYPE, type = CommandType.STRING, description = "Guest type of the network offering: Shared or Isolated")
private String guestIptype;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getSourceOfferingId() {
return sourceOfferingId;
}
public List<String> getAddServices() {
return addServices;
}
public List<String> getDropServices() {
return dropServices;
}
public String getGuestIpType() {
return guestIptype;
}
public String getTraffictype() {
return traffictype;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
NetworkOffering result = _configService.cloneNetworkOffering(this);
if (result != null) {
NetworkOfferingResponse response = _responseGenerator.createNetworkOfferingResponse(result);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone network offering");
}
}
}

View File

@ -16,505 +16,47 @@
// under the License.
package org.apache.cloudstack.api.command.admin.network;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.cloud.network.Network;
import com.cloud.network.VirtualRouterProvider;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.cloudstack.api.APICommand;
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.NetworkOfferingResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Service;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.NetworkOffering.Availability;
import com.cloud.user.Account;
import static com.cloud.network.Network.Service.Dhcp;
import static com.cloud.network.Network.Service.Dns;
import static com.cloud.network.Network.Service.Lb;
import static com.cloud.network.Network.Service.StaticNat;
import static com.cloud.network.Network.Service.SourceNat;
import static com.cloud.network.Network.Service.PortForwarding;
import static com.cloud.network.Network.Service.NetworkACL;
import static com.cloud.network.Network.Service.UserData;
import static com.cloud.network.Network.Service.Firewall;
import static org.apache.cloudstack.api.command.utils.OfferingUtils.isNetrisNatted;
import static org.apache.cloudstack.api.command.utils.OfferingUtils.isNetrisRouted;
import static org.apache.cloudstack.api.command.utils.OfferingUtils.isNsxWithoutLb;
@APICommand(name = "createNetworkOffering", description = "Creates a network offering.", responseObject = NetworkOfferingResponse.class, since = "3.0.0",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class CreateNetworkOfferingCmd extends BaseCmd {
public class CreateNetworkOfferingCmd extends NetworkOfferingBaseCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "The name of the network offering")
private String networkOfferingName;
@Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "The display text of the network offering, defaults to the value of 'name'.")
private String displayText;
@Parameter(name = ApiConstants.TRAFFIC_TYPE,
type = CommandType.STRING,
required = true,
description = "The traffic type for the network offering. Supported type in current release is GUEST only")
private String traffictype;
@Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "The tags for the network offering.", length = 4096)
private String tags;
@Parameter(name = ApiConstants.SPECIFY_VLAN, type = CommandType.BOOLEAN, description = "True if network offering supports VLANs")
private Boolean specifyVlan;
@Parameter(name = ApiConstants.AVAILABILITY, type = CommandType.STRING, description = "The availability of network offering. The default value is Optional. "
+ " Another value is Required, which will make it as the default network offering for new networks ")
private String availability;
@Parameter(name = ApiConstants.NETWORKRATE, type = CommandType.INTEGER, description = "Data transfer rate in megabits per second allowed")
private Integer networkRate;
@Parameter(name = ApiConstants.CONSERVE_MODE, type = CommandType.BOOLEAN, description = "True if the network offering is IP conserve mode enabled")
private Boolean conserveMode;
@Parameter(name = ApiConstants.SERVICE_OFFERING_ID,
type = CommandType.UUID,
entityType = ServiceOfferingResponse.class,
description = "The service offering ID used by virtual router provider")
private Long serviceOfferingId;
@Parameter(name = ApiConstants.GUEST_IP_TYPE, type = CommandType.STRING, required = true, description = "Guest type of the network offering: Shared or Isolated")
private String guestIptype;
@Parameter(name = ApiConstants.INTERNET_PROTOCOL,
type = CommandType.STRING,
description = "The internet protocol of network offering. Options are IPv4 and dualstack. Default is IPv4. dualstack will create a network offering that supports both IPv4 and IPv6",
since = "4.17.0")
private String internetProtocol;
@Parameter(name = ApiConstants.SUPPORTED_SERVICES,
type = CommandType.LIST,
collectionType = CommandType.STRING,
description = "Services supported by the network offering")
private List<String> supportedServices;
@Parameter(name = ApiConstants.SERVICE_PROVIDER_LIST,
type = CommandType.MAP,
description = "Provider to service mapping. If not specified, the provider for the service will be mapped to the default provider on the physical network")
private Map serviceProviderList;
@Parameter(name = ApiConstants.SERVICE_CAPABILITY_LIST, type = CommandType.MAP, description = "Desired service capabilities as part of network offering")
private Map serviceCapabilitystList;
@Parameter(name = ApiConstants.SPECIFY_IP_RANGES,
type = CommandType.BOOLEAN,
description = "True if network offering supports specifying ip ranges; defaulted to false if not specified")
private Boolean specifyIpRanges;
@Parameter(name = ApiConstants.IS_PERSISTENT,
type = CommandType.BOOLEAN,
description = "True if network offering supports persistent networks; defaulted to false if not specified")
private Boolean isPersistent;
@Parameter(name = ApiConstants.FOR_VPC,
type = CommandType.BOOLEAN,
description = "True if network offering is meant to be used for VPC, false otherwise.")
private Boolean forVpc;
@Deprecated
@Parameter(name = ApiConstants.FOR_NSX,
type = CommandType.BOOLEAN,
description = "true if network offering is meant to be used for NSX, false otherwise.",
since = "4.20.0")
private Boolean forNsx;
@Parameter(name = ApiConstants.PROVIDER,
type = CommandType.STRING,
description = "Name of the provider providing the service",
since = "4.21.0")
private String provider;
@Parameter(name = ApiConstants.NSX_SUPPORT_LB,
type = CommandType.BOOLEAN,
description = "True if network offering for NSX network offering supports Load balancer service.",
since = "4.20.0")
private Boolean nsxSupportsLbService;
@Parameter(name = ApiConstants.NSX_SUPPORTS_INTERNAL_LB,
type = CommandType.BOOLEAN,
description = "True if network offering for NSX network offering supports Internal Load balancer service.",
since = "4.20.0")
private Boolean nsxSupportsInternalLbService;
@Parameter(name = ApiConstants.NETWORK_MODE,
type = CommandType.STRING,
description = "Indicates the mode with which the network will operate. Valid option: NATTED or ROUTED",
since = "4.20.0")
private String networkMode;
@Parameter(name = ApiConstants.FOR_TUNGSTEN,
type = CommandType.BOOLEAN,
description = "True if network offering is meant to be used for Tungsten-Fabric, false otherwise.")
private Boolean forTungsten;
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.2.0", description = "Network offering details in key/value pairs."
+ " Supported keys are internallbprovider/publiclbprovider with service provider as a value, and"
+ " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup")
protected Map details;
@Parameter(name = ApiConstants.EGRESS_DEFAULT_POLICY,
type = CommandType.BOOLEAN,
description = "True if guest network default egress policy is allow; false if default egress policy is deny")
private Boolean egressDefaultPolicy;
@Parameter(name = ApiConstants.KEEPALIVE_ENABLED,
type = CommandType.BOOLEAN,
required = false,
description = "If true keepalive will be turned on in the loadbalancer. At the time of writing this has only an effect on haproxy; the mode http and httpclose options are unset in the haproxy conf file.")
private Boolean keepAliveEnabled;
@Parameter(name = ApiConstants.MAX_CONNECTIONS,
type = CommandType.INTEGER,
description = "Maximum number of concurrent connections supported by the Network offering")
private Integer maxConnections;
@Parameter(name = ApiConstants.DOMAIN_ID,
type = CommandType.LIST,
collectionType = CommandType.UUID,
entityType = DomainResponse.class,
description = "The ID of the containing domain(s), null for public offerings")
private List<Long> domainIds;
@Parameter(name = ApiConstants.ZONE_ID,
type = CommandType.LIST,
collectionType = CommandType.UUID,
entityType = ZoneResponse.class,
description = "The ID of the containing zone(s), null for public offerings",
since = "4.13")
private List<Long> zoneIds;
@Parameter(name = ApiConstants.ENABLE,
type = CommandType.BOOLEAN,
description = "Set to true if the offering is to be enabled during creation. Default is false",
since = "4.16")
private Boolean enable;
@Parameter(name = ApiConstants.SPECIFY_AS_NUMBER, type = CommandType.BOOLEAN, since = "4.20.0",
description = "true if network offering supports choosing AS number")
private Boolean specifyAsNumber;
@Parameter(name = ApiConstants.ROUTING_MODE,
type = CommandType.STRING,
since = "4.20.0",
description = "the routing mode for the network offering. Supported types are: Static or Dynamic.")
private String routingMode;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getNetworkOfferingName() {
return networkOfferingName;
}
public String getDisplayText() {
return StringUtils.isEmpty(displayText) ? networkOfferingName : displayText;
}
public String getTags() {
return tags;
}
public String getTraffictype() {
return traffictype;
}
public Boolean getSpecifyVlan() {
return specifyVlan == null ? false : specifyVlan;
}
public String getAvailability() {
return availability == null ? Availability.Optional.toString() : availability;
}
public Integer getNetworkRate() {
return networkRate;
}
public Long getServiceOfferingId() {
return serviceOfferingId;
}
public boolean isExternalNetworkProvider() {
return Arrays.asList("NSX", "Netris").stream()
.anyMatch(s -> provider != null && s.equalsIgnoreCase(provider));
}
public boolean isForNsx() {
return provider != null && provider.equalsIgnoreCase("NSX");
}
public boolean isForNetris() {
return provider != null && provider.equalsIgnoreCase("Netris");
}
public String getProvider() {
return provider;
}
public List<String> getSupportedServices() {
if (!isExternalNetworkProvider()) {
return supportedServices == null ? new ArrayList<String>() : supportedServices;
} else {
List<String> services = new ArrayList<>(List.of(
Dhcp.getName(),
Dns.getName(),
UserData.getName()
));
if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode())) {
services.addAll(Arrays.asList(
StaticNat.getName(),
SourceNat.getName(),
PortForwarding.getName()));
}
if (getNsxSupportsLbService() || (provider != null && isNetrisNatted(getProvider(), getNetworkMode()))) {
services.add(Lb.getName());
}
if (Boolean.TRUE.equals(forVpc)) {
services.add(NetworkACL.getName());
} else {
services.add(Firewall.getName());
}
return services;
}
}
public String getGuestIpType() {
return guestIptype;
}
public String getInternetProtocol() {
return internetProtocol;
}
public Boolean getSpecifyIpRanges() {
return specifyIpRanges == null ? false : specifyIpRanges;
}
public Boolean getConserveMode() {
if (conserveMode == null) {
return true;
}
return conserveMode;
}
public Boolean getIsPersistent() {
return isPersistent == null ? false : isPersistent;
}
public Boolean getForVpc() {
return forVpc;
}
public String getNetworkMode() {
return networkMode;
}
public boolean getNsxSupportsLbService() {
return BooleanUtils.isTrue(nsxSupportsLbService);
}
public boolean getNsxSupportsInternalLbService() {
return BooleanUtils.isTrue(nsxSupportsInternalLbService);
}
public Boolean getForTungsten() {
return forTungsten;
}
public Boolean getEgressDefaultPolicy() {
if (egressDefaultPolicy == null) {
return true;
}
return egressDefaultPolicy;
}
public Boolean getKeepAliveEnabled() {
return keepAliveEnabled;
}
public Integer getMaxconnections() {
return maxConnections;
}
public Map<String, List<String>> getServiceProviders() {
Map<String, List<String>> serviceProviderMap = new HashMap<>();
if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isExternalNetworkProvider()) {
Collection servicesCollection = serviceProviderList.values();
Iterator iter = servicesCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> services = (HashMap<String, String>) iter.next();
String service = services.get("service");
String provider = services.get("provider");
List<String> providerList = null;
if (serviceProviderMap.containsKey(service)) {
providerList = serviceProviderMap.get(service);
} else {
providerList = new ArrayList<String>();
}
providerList.add(provider);
serviceProviderMap.put(service, providerList);
}
} else if (isExternalNetworkProvider()) {
getServiceProviderMapForExternalProvider(serviceProviderMap, Network.Provider.getProvider(provider).getName());
}
return serviceProviderMap;
}
private void getServiceProviderMapForExternalProvider(Map<String, List<String>> serviceProviderMap, String provider) {
String routerProvider = Boolean.TRUE.equals(getForVpc()) ? VirtualRouterProvider.Type.VPCVirtualRouter.name() :
VirtualRouterProvider.Type.VirtualRouter.name();
List<String> unsupportedServices = new ArrayList<>(List.of("Vpn", "Gateway", "SecurityGroup", "Connectivity", "BaremetalPxeService"));
List<String> routerSupported = List.of("Dhcp", "Dns", "UserData");
List<String> allServices = Service.listAllServices().stream().map(Service::getName).collect(Collectors.toList());
if (routerProvider.equals(VirtualRouterProvider.Type.VPCVirtualRouter.name())) {
unsupportedServices.add("Firewall");
} else {
unsupportedServices.add("NetworkACL");
}
for (String service : allServices) {
if (unsupportedServices.contains(service))
continue;
if (routerSupported.contains(service))
serviceProviderMap.put(service, List.of(routerProvider));
else if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode()) || NetworkACL.getName().equalsIgnoreCase(service)) {
serviceProviderMap.put(service, List.of(provider));
}
if (isNsxWithoutLb(getProvider(), getNsxSupportsLbService()) || isNetrisRouted(getProvider(), getNetworkMode())) {
serviceProviderMap.remove(Lb.getName());
}
}
}
public Map<Capability, String> getServiceCapabilities(Service service) {
Map<Capability, String> capabilityMap = null;
if (serviceCapabilitystList != null && !serviceCapabilitystList.isEmpty()) {
capabilityMap = new HashMap<Capability, String>();
Collection serviceCapabilityCollection = serviceCapabilitystList.values();
Iterator iter = serviceCapabilityCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> svcCapabilityMap = (HashMap<String, String>) iter.next();
Capability capability = null;
String svc = svcCapabilityMap.get("service");
String capabilityName = svcCapabilityMap.get("capabilitytype");
String capabilityValue = svcCapabilityMap.get("capabilityvalue");
if (capabilityName != null) {
capability = Capability.getCapability(capabilityName);
}
if ((capability == null) || (capabilityName == null) || (capabilityValue == null)) {
throw new InvalidParameterValueException("Invalid capability:" + capabilityName + " capability value:" + capabilityValue);
}
if (svc.equalsIgnoreCase(service.getName())) {
capabilityMap.put(capability, capabilityValue);
} else {
//throw new InvalidParameterValueException("Service is not equal ")
}
}
}
return capabilityMap;
}
public Map<String, String> getDetails() {
if (details == null || details.isEmpty()) {
return null;
}
Collection paramsCollection = details.values();
Object objlist[] = paramsCollection.toArray();
Map<String, String> params = (Map<String, String>) (objlist[0]);
for (int i = 1; i < objlist.length; i++) {
params.putAll((Map<String, String>) (objlist[i]));
}
return params;
}
public String getServicePackageId() {
Map<String, String> data = getDetails();
if (data == null)
return null;
return data.get(NetworkOffering.Detail.servicepackageuuid + "");
}
public List<Long> getDomainIds() {
if (CollectionUtils.isNotEmpty(domainIds)) {
Set<Long> set = new LinkedHashSet<>(domainIds);
domainIds.clear();
domainIds.addAll(set);
}
return domainIds;
}
public List<Long> getZoneIds() {
if (CollectionUtils.isNotEmpty(zoneIds)) {
Set<Long> set = new LinkedHashSet<>(zoneIds);
zoneIds.clear();
zoneIds.addAll(set);
}
return zoneIds;
}
public Boolean getEnable() {
if (enable != null) {
return enable;
}
return false;
}
public boolean getSpecifyAsNumber() {
return BooleanUtils.toBoolean(specifyAsNumber);
}
public String getRoutingMode() {
return routingMode;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() {

View File

@ -75,7 +75,7 @@ public class CreatePhysicalNetworkCmd extends BaseAsyncCreateCmd {
@Parameter(name = ApiConstants.ISOLATION_METHODS,
type = CommandType.LIST,
collectionType = CommandType.STRING,
description = "The isolation method for the physical Network[VLAN/L3/GRE]")
description = "The isolation method for the physical Network[VLAN/VXLAN/GRE/STT/BCF_SEGMENT/SSP/ODL/L3VPN/VCS/NSX/NETRIS]")
private List<String> isolationMethods;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "The name of the physical Network")

View File

@ -0,0 +1,493 @@
// 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.network;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.Network;
import com.cloud.network.VirtualRouterProvider;
import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.cloud.network.Network.Service.Dhcp;
import static com.cloud.network.Network.Service.Dns;
import static com.cloud.network.Network.Service.Firewall;
import static com.cloud.network.Network.Service.Lb;
import static com.cloud.network.Network.Service.NetworkACL;
import static com.cloud.network.Network.Service.PortForwarding;
import static com.cloud.network.Network.Service.SourceNat;
import static com.cloud.network.Network.Service.StaticNat;
import static com.cloud.network.Network.Service.UserData;
import static org.apache.cloudstack.api.command.utils.OfferingUtils.isNsxWithoutLb;
import static org.apache.cloudstack.api.command.utils.OfferingUtils.isNetrisNatted;
import static org.apache.cloudstack.api.command.utils.OfferingUtils.isNetrisRouted;
public abstract class NetworkOfferingBaseCmd extends BaseCmd {
public abstract String getGuestIpType();
public abstract String getTraffictype();
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "The name of the network offering")
private String networkOfferingName;
@Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "The display text of the network offering, defaults to the value of 'name'.")
private String displayText;
@Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "The tags for the network offering.", length = 4096)
private String tags;
@Parameter(name = ApiConstants.SPECIFY_VLAN, type = CommandType.BOOLEAN, description = "True if network offering supports VLANs")
private Boolean specifyVlan;
@Parameter(name = ApiConstants.AVAILABILITY, type = CommandType.STRING, description = "The availability of network offering. The default value is Optional. "
+ " Another value is Required, which will make it as the default network offering for new networks ")
private String availability;
@Parameter(name = ApiConstants.NETWORKRATE, type = CommandType.INTEGER, description = "Data transfer rate in megabits per second allowed")
private Integer networkRate;
@Parameter(name = ApiConstants.CONSERVE_MODE, type = CommandType.BOOLEAN, description = "True if the network offering is IP conserve mode enabled")
private Boolean conserveMode;
@Parameter(name = ApiConstants.SERVICE_OFFERING_ID,
type = CommandType.UUID,
entityType = ServiceOfferingResponse.class,
description = "The service offering ID used by virtual router provider")
private Long serviceOfferingId;
@Parameter(name = ApiConstants.INTERNET_PROTOCOL,
type = CommandType.STRING,
description = "The internet protocol of network offering. Options are IPv4 and dualstack. Default is IPv4. dualstack will create a network offering that supports both IPv4 and IPv6",
since = "4.17.0")
private String internetProtocol;
@Parameter(name = ApiConstants.SUPPORTED_SERVICES,
type = CommandType.LIST,
collectionType = CommandType.STRING,
description = "Services supported by the network offering")
private List<String> supportedServices;
@Parameter(name = ApiConstants.SERVICE_PROVIDER_LIST,
type = CommandType.MAP,
description = "Provider to service mapping. If not specified, the provider for the service will be mapped to the default provider on the physical network")
private Map serviceProviderList;
@Parameter(name = ApiConstants.SERVICE_CAPABILITY_LIST, type = CommandType.MAP, description = "Desired service capabilities as part of network offering")
private Map serviceCapabilitiesList;
@Parameter(name = ApiConstants.SPECIFY_IP_RANGES,
type = CommandType.BOOLEAN,
description = "True if network offering supports specifying ip ranges; defaulted to false if not specified")
private Boolean specifyIpRanges;
@Parameter(name = ApiConstants.IS_PERSISTENT,
type = CommandType.BOOLEAN,
description = "True if network offering supports persistent networks; defaulted to false if not specified")
private Boolean isPersistent;
@Parameter(name = ApiConstants.FOR_VPC,
type = CommandType.BOOLEAN,
description = "True if network offering is meant to be used for VPC, false otherwise.")
private Boolean forVpc;
@Deprecated
@Parameter(name = ApiConstants.FOR_NSX,
type = CommandType.BOOLEAN,
description = "true if network offering is meant to be used for NSX, false otherwise.",
since = "4.20.0")
private Boolean forNsx;
@Parameter(name = ApiConstants.PROVIDER,
type = CommandType.STRING,
description = "Name of the provider providing the service",
since = "4.21.0")
private String provider;
@Parameter(name = ApiConstants.NSX_SUPPORT_LB,
type = CommandType.BOOLEAN,
description = "True if network offering for NSX network offering supports Load balancer service.",
since = "4.20.0")
private Boolean nsxSupportsLbService;
@Parameter(name = ApiConstants.NSX_SUPPORTS_INTERNAL_LB,
type = CommandType.BOOLEAN,
description = "True if network offering for NSX network offering supports Internal Load balancer service.",
since = "4.20.0")
private Boolean nsxSupportsInternalLbService;
@Parameter(name = ApiConstants.NETWORK_MODE,
type = CommandType.STRING,
description = "Indicates the mode with which the network will operate. Valid option: NATTED or ROUTED",
since = "4.20.0")
private String networkMode;
@Parameter(name = ApiConstants.FOR_TUNGSTEN,
type = CommandType.BOOLEAN,
description = "True if network offering is meant to be used for Tungsten-Fabric, false otherwise.")
private Boolean forTungsten;
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.2.0", description = "Network offering details in key/value pairs."
+ " Supported keys are internallbprovider/publiclbprovider with service provider as a value, and"
+ " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup")
protected Map details;
@Parameter(name = ApiConstants.EGRESS_DEFAULT_POLICY,
type = CommandType.BOOLEAN,
description = "True if guest network default egress policy is allow; false if default egress policy is deny")
private Boolean egressDefaultPolicy;
@Parameter(name = ApiConstants.KEEPALIVE_ENABLED,
type = CommandType.BOOLEAN,
required = false,
description = "If true keepalive will be turned on in the loadbalancer. At the time of writing this has only an effect on haproxy; the mode http and httpclose options are unset in the haproxy conf file.")
private Boolean keepAliveEnabled;
@Parameter(name = ApiConstants.MAX_CONNECTIONS,
type = CommandType.INTEGER,
description = "Maximum number of concurrent connections supported by the Network offering")
private Integer maxConnections;
@Parameter(name = ApiConstants.DOMAIN_ID,
type = CommandType.LIST,
collectionType = CommandType.UUID,
entityType = DomainResponse.class,
description = "The ID of the containing domain(s), null for public offerings")
private List<Long> domainIds;
@Parameter(name = ApiConstants.ZONE_ID,
type = CommandType.LIST,
collectionType = CommandType.UUID,
entityType = ZoneResponse.class,
description = "The ID of the containing zone(s), null for public offerings",
since = "4.13")
private List<Long> zoneIds;
@Parameter(name = ApiConstants.ENABLE,
type = CommandType.BOOLEAN,
description = "Set to true if the offering is to be enabled during creation. Default is false",
since = "4.16")
private Boolean enable;
@Parameter(name = ApiConstants.SPECIFY_AS_NUMBER, type = CommandType.BOOLEAN, since = "4.20.0",
description = "true if network offering supports choosing AS number")
private Boolean specifyAsNumber;
@Parameter(name = ApiConstants.ROUTING_MODE,
type = CommandType.STRING,
since = "4.20.0",
description = "the routing mode for the network offering. Supported types are: Static or Dynamic.")
private String routingMode;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getNetworkOfferingName() {
return networkOfferingName;
}
public String getDisplayText() {
return StringUtils.isEmpty(displayText) ? networkOfferingName : displayText;
}
public String getTags() {
return tags;
}
public Boolean getSpecifyVlan() {
return specifyVlan == null ? false : specifyVlan;
}
public String getAvailability() {
return availability == null ? NetworkOffering.Availability.Optional.toString() : availability;
}
public Integer getNetworkRate() {
return networkRate;
}
public Long getServiceOfferingId() {
return serviceOfferingId;
}
public boolean isExternalNetworkProvider() {
return Arrays.asList("NSX", "Netris").stream()
.anyMatch(s -> provider != null && s.equalsIgnoreCase(provider));
}
public boolean isForNsx() {
return provider != null && provider.equalsIgnoreCase("NSX");
}
public boolean isForNetris() {
return provider != null && provider.equalsIgnoreCase("Netris");
}
public String getProvider() {
return provider;
}
public List<String> getSupportedServices() {
if (!isExternalNetworkProvider()) {
return supportedServices == null ? new ArrayList<String>() : supportedServices;
} else {
List<String> services = new ArrayList<>(List.of(
Dhcp.getName(),
Dns.getName(),
UserData.getName()
));
if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode())) {
services.addAll(Arrays.asList(
StaticNat.getName(),
SourceNat.getName(),
PortForwarding.getName()));
}
if (getNsxSupportsLbService() || (provider != null && isNetrisNatted(getProvider(), getNetworkMode()))) {
services.add(Lb.getName());
}
if (Boolean.TRUE.equals(forVpc)) {
services.add(NetworkACL.getName());
} else {
services.add(Firewall.getName());
}
return services;
}
}
public String getInternetProtocol() {
return internetProtocol;
}
public Boolean getSpecifyIpRanges() {
return specifyIpRanges == null ? false : specifyIpRanges;
}
public Boolean getConserveMode() {
if (conserveMode == null) {
return true;
}
return conserveMode;
}
public Boolean getIsPersistent() {
return isPersistent == null ? false : isPersistent;
}
public Boolean getForVpc() {
return forVpc;
}
public String getNetworkMode() {
return networkMode;
}
public boolean getNsxSupportsLbService() {
return BooleanUtils.isTrue(nsxSupportsLbService);
}
public boolean getNsxSupportsInternalLbService() {
return BooleanUtils.isTrue(nsxSupportsInternalLbService);
}
public Boolean getForTungsten() {
return forTungsten;
}
public Boolean getEgressDefaultPolicy() {
if (egressDefaultPolicy == null) {
return true;
}
return egressDefaultPolicy;
}
public Boolean getKeepAliveEnabled() {
return keepAliveEnabled;
}
public Integer getMaxconnections() {
return maxConnections;
}
public Map<String, List<String>> getServiceProviders() {
Map<String, List<String>> serviceProviderMap = new HashMap<>();
if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isExternalNetworkProvider()) {
Collection servicesCollection = serviceProviderList.values();
Iterator iter = servicesCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> services = (HashMap<String, String>) iter.next();
String service = services.get("service");
String provider = services.get("provider");
List<String> providerList = null;
if (serviceProviderMap.containsKey(service)) {
providerList = serviceProviderMap.get(service);
} else {
providerList = new ArrayList<String>();
}
providerList.add(provider);
serviceProviderMap.put(service, providerList);
}
} else if (isExternalNetworkProvider()) {
getServiceProviderMapForExternalProvider(serviceProviderMap, Network.Provider.getProvider(provider).getName());
}
return serviceProviderMap;
}
private void getServiceProviderMapForExternalProvider(Map<String, List<String>> serviceProviderMap, String provider) {
String routerProvider = Boolean.TRUE.equals(getForVpc()) ? VirtualRouterProvider.Type.VPCVirtualRouter.name() :
VirtualRouterProvider.Type.VirtualRouter.name();
List<String> unsupportedServices = new ArrayList<>(List.of("Vpn", "Gateway", "SecurityGroup", "Connectivity", "BaremetalPxeService"));
List<String> routerSupported = List.of("Dhcp", "Dns", "UserData");
List<String> allServices = Network.Service.listAllServices().stream().map(Network.Service::getName).collect(Collectors.toList());
if (routerProvider.equals(VirtualRouterProvider.Type.VPCVirtualRouter.name())) {
unsupportedServices.add("Firewall");
} else {
unsupportedServices.add("NetworkACL");
}
for (String service : allServices) {
if (unsupportedServices.contains(service))
continue;
if (routerSupported.contains(service))
serviceProviderMap.put(service, List.of(routerProvider));
else if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode()) || NetworkACL.getName().equalsIgnoreCase(service)) {
serviceProviderMap.put(service, List.of(provider));
}
if (isNsxWithoutLb(getProvider(), getNsxSupportsLbService()) || isNetrisRouted(getProvider(), getNetworkMode())) {
serviceProviderMap.remove(Lb.getName());
}
}
}
public Map<Network.Capability, String> getServiceCapabilities(Network.Service service) {
Map<Network.Capability, String> capabilityMap = null;
if (serviceCapabilitiesList != null && !serviceCapabilitiesList.isEmpty()) {
capabilityMap = new HashMap<Network.Capability, String>();
Collection serviceCapabilityCollection = serviceCapabilitiesList.values();
Iterator iter = serviceCapabilityCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> svcCapabilityMap = (HashMap<String, String>) iter.next();
Network.Capability capability = null;
String svc = svcCapabilityMap.get("service");
String capabilityName = svcCapabilityMap.get("capabilitytype");
String capabilityValue = svcCapabilityMap.get("capabilityvalue");
if (capabilityName != null) {
capability = Network.Capability.getCapability(capabilityName);
}
if ((capability == null) || (capabilityName == null) || (capabilityValue == null)) {
throw new InvalidParameterValueException("Invalid capability:" + capabilityName + " capability value:" + capabilityValue);
}
if (svc.equalsIgnoreCase(service.getName())) {
capabilityMap.put(capability, capabilityValue);
} else {
//throw new InvalidParameterValueException("Service is not equal ")
}
}
}
return capabilityMap;
}
public Map<String, String> getDetails() {
if (details == null || details.isEmpty()) {
return null;
}
Collection paramsCollection = details.values();
Object objlist[] = paramsCollection.toArray();
Map<String, String> params = (Map<String, String>) (objlist[0]);
for (int i = 1; i < objlist.length; i++) {
params.putAll((Map<String, String>) (objlist[i]));
}
return params;
}
public String getServicePackageId() {
Map<String, String> data = getDetails();
if (data == null)
return null;
return data.get(NetworkOffering.Detail.servicepackageuuid + "");
}
public List<Long> getDomainIds() {
if (CollectionUtils.isNotEmpty(domainIds)) {
Set<Long> set = new LinkedHashSet<>(domainIds);
domainIds.clear();
domainIds.addAll(set);
}
return domainIds;
}
public List<Long> getZoneIds() {
if (CollectionUtils.isNotEmpty(zoneIds)) {
Set<Long> set = new LinkedHashSet<>(zoneIds);
zoneIds.clear();
zoneIds.addAll(set);
}
return zoneIds;
}
public Boolean getEnable() {
if (enable != null) {
return enable;
}
return false;
}
public boolean getSpecifyAsNumber() {
return BooleanUtils.toBoolean(specifyAsNumber);
}
public String getRoutingMode() {
return routingMode;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,73 @@
// 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.offering;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
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.DiskOfferingResponse;
import com.cloud.offering.DiskOffering;
@APICommand(name = "cloneDiskOffering",
description = "Clones a disk offering. All parameters from createDiskOffering are available. If not specified, values will be copied from the source offering.",
responseObject = DiskOfferingResponse.class,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false,
since = "4.23.0",
authorized = {RoleType.Admin, RoleType.DomainAdmin})
public class CloneDiskOfferingCmd extends CreateDiskOfferingCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.SOURCE_OFFERING_ID,
type = BaseCmd.CommandType.UUID,
entityType = DiskOfferingResponse.class,
required = true,
description = "The ID of the source disk offering to clone from")
private Long sourceOfferingId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getSourceOfferingId() {
return sourceOfferingId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
DiskOffering result = _configService.cloneDiskOffering(this);
if (result != null) {
DiskOfferingResponse response = _responseGenerator.createDiskOfferingResponse(result);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone disk offering");
}
}
}

View File

@ -0,0 +1,79 @@
// 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.offering;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import com.cloud.offering.ServiceOffering;
@APICommand(name = "cloneServiceOffering",
description = "Clones a service offering. All parameters from createServiceOffering are available. If not specified, values will be copied from the source offering.",
responseObject = ServiceOfferingResponse.class,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false,
since = "4.23.0",
authorized = {RoleType.Admin, RoleType.DomainAdmin})
public class CloneServiceOfferingCmd extends CreateServiceOfferingCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.SOURCE_OFFERING_ID,
type = CommandType.UUID,
entityType = ServiceOfferingResponse.class,
required = true,
description = "The ID of the source service offering to clone from")
private Long sourceOfferingId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getSourceOfferingId() {
return sourceOfferingId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
try {
ServiceOffering result = _configService.cloneServiceOffering(this);
if (result != null) {
ServiceOfferingResponse response = _responseGenerator.createServiceOfferingResponse(result);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone service offering");
}
} catch (com.cloud.exception.InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage());
} catch (com.cloud.utils.exception.CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
}

View File

@ -27,7 +27,7 @@ import static org.apache.cloudstack.api.ApiConstants.S3_END_POINT;
import static org.apache.cloudstack.api.ApiConstants.S3_HTTPS_FLAG;
import static org.apache.cloudstack.api.ApiConstants.S3_MAX_ERROR_RETRY;
import static org.apache.cloudstack.api.ApiConstants.S3_SIGNER;
import static org.apache.cloudstack.api.ApiConstants.S3_SECRET_KEY;
import static org.apache.cloudstack.api.ApiConstants.SECRET_KEY;
import static org.apache.cloudstack.api.ApiConstants.S3_SOCKET_TIMEOUT;
import static org.apache.cloudstack.api.ApiConstants.S3_USE_TCP_KEEPALIVE;
import static org.apache.cloudstack.api.BaseCmd.CommandType.BOOLEAN;
@ -64,7 +64,7 @@ public final class AddImageStoreS3CMD extends BaseCmd implements ClientOptions {
@Parameter(name = S3_ACCESS_KEY, type = STRING, required = true, description = "S3 access key")
private String accessKey;
@Parameter(name = S3_SECRET_KEY, type = STRING, required = true, description = "S3 secret key")
@Parameter(name = SECRET_KEY, type = STRING, required = true, description = "S3 secret key")
private String secretKey;
@Parameter(name = S3_END_POINT, type = STRING, required = true, description = "S3 endpoint")
@ -101,7 +101,7 @@ public final class AddImageStoreS3CMD extends BaseCmd implements ClientOptions {
Map<String, String> dm = new HashMap();
dm.put(ApiConstants.S3_ACCESS_KEY, getAccessKey());
dm.put(ApiConstants.S3_SECRET_KEY, getSecretKey());
dm.put(ApiConstants.SECRET_KEY, getSecretKey());
dm.put(ApiConstants.S3_END_POINT, getEndPoint());
dm.put(ApiConstants.S3_BUCKET_NAME, getBucketName());

View File

@ -0,0 +1,81 @@
// 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.user;
import com.cloud.event.EventTypes;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPair;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ApiKeyPairResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
@APICommand(name = "deleteUserKeys", description = "Deletes a keypair from a user", responseObject = SuccessResponse.class,
since = "4.23.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class DeleteUserKeysCmd extends BaseAsyncCmd {
@ACL
@Parameter(name = ApiConstants.KEYPAIR_ID, type = CommandType.UUID, entityType = ApiKeyPairResponse.class, required = true, description = "ID of the keypair to be deleted.")
private Long id;
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.User;
}
@Override
public long getEntityOwnerId() {
ApiKeyPair keyPair = apiKeyPairService.findById(id);
if (keyPair != null) {
return keyPair.getAccountId();
}
return Account.ACCOUNT_ID_SYSTEM;
}
public Long getId() {
return id;
}
@Override
public void execute() {
_accountService.deleteApiKey(this);
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
}
@Override
public String getEventType() {
return EventTypes.EVENT_DELETE_SECRET_API_KEY;
}
@Override
public String getEventDescription() {
ApiKeyPair keyPair = apiKeyPairService.findById(id);
return String.format("Deleting API key pair with ID [%s]%s",
keyPair == null ? id : keyPair.getUuid(),
keyPair == null ? "." : String.format(" and name [%s].", keyPair.getName()));
}
@Override
public Long getSyncObjId() {
return getId();
}
}

View File

@ -32,33 +32,33 @@ import org.apache.cloudstack.api.response.UserResponse;
import java.util.Map;
@APICommand(name = "getUserKeys",
description = "This command allows the user to query the seceret and API keys for the account",
responseObject = RegisterUserKeyResponse.class,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = true,
authorized = {RoleType.User, RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin},
since = "4.10.0")
public class GetUserKeysCmd extends BaseCmd{
@Parameter(name= ApiConstants.ID, type = CommandType.UUID, entityType = UserResponse.class, required = true, description = "ID of the user whose keys are required")
description = "Queries the last registered secret and API keys of a user.",
responseObject = RegisterUserKeyResponse.class,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = true,
authorized = {RoleType.User, RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin},
since = "4.10.0")
public class GetUserKeysCmd extends BaseCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserResponse.class, required = true, description = "ID of the user whose keys are required")
private Long id;
public Long getID(){
public Long getId() {
return id;
}public long getEntityOwnerId(){
User user = _entityMgr.findById(User.class, getID());
if(user != null){
}
public long getEntityOwnerId() {
User user = _entityMgr.findById(User.class, getId());
if (user != null) {
return user.getAccountId();
}
else return Account.ACCOUNT_ID_SYSTEM;
return Account.ACCOUNT_ID_SYSTEM;
}
public void execute(){
public void execute() {
Pair<Boolean, Map<String, String>> keys = _accountService.getKeys(this);
RegisterUserKeyResponse response = new RegisterUserKeyResponse();
if(keys != null){
if (keys != null){
response.setApiKeyAccess(keys.first());
response.setApiKey(keys.second().get("apikey"));
response.setSecretKey(keys.second().get("secretkey"));

View File

@ -0,0 +1,68 @@
// 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.user;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPair;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ApiKeyPairResponse;
import org.apache.cloudstack.api.response.BaseRolePermissionResponse;
import org.apache.cloudstack.api.response.ListResponse;
import java.util.List;
@APICommand(name = "listUserKeyRules",
description = "Lists the rules defined for a API key pair.",
responseObject = BaseRolePermissionResponse.class,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false,
since = "4.23.0")
public class ListUserKeyRulesCmd extends BaseCmd {
@ACL
@Parameter(name = ApiConstants.KEYPAIR_ID, type = CommandType.UUID, entityType = ApiKeyPairResponse.class, description = "ID of the key pair.", required = true)
private Long id;
public Long getId() {
return id;
}
public long getEntityOwnerId() {
ApiKeyPair keyPair = apiKeyPairService.findById(getId());
if (keyPair != null) {
return keyPair.getAccountId();
}
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException {
List<ApiKeyPairPermission> permissions = _accountService.listKeyRules(this);
ListResponse<BaseRolePermissionResponse> response = _responseGenerator.createKeypairPermissionsResponse(permissions);
response.setResponseName(getCommandName());
setResponseObject(response);
}
}

View File

@ -0,0 +1,101 @@
// 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.user;
import com.cloud.user.Account;
import com.cloud.user.UserAccount;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPair;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ApiKeyPairResponse;
import org.apache.cloudstack.api.response.UserResponse;
@APICommand(name = "listUserKeys",
description = "Lists the API key pairs (API and secret keys) of a user.",
responseObject = ApiKeyPairResponse.class,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = true,
authorized = {RoleType.User, RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin},
since = "4.23.0")
public class ListUserKeysCmd extends BaseListCmd {
@ACL
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, description = "ID of the user that owns the keys.")
private Long userId;
@ACL
@Parameter(name = ApiConstants.KEYPAIR_ID, type = CommandType.UUID, entityType = ApiKeyPairResponse.class, description = "ID of the key pair.")
private Long keyPairId;
@Parameter(name = ApiConstants.API_KEY_FILTER, type = CommandType.STRING, description = "API key of the key pair.")
private String apiKeyFilter;
@Parameter(name = ApiConstants.SHOW_PERMISSIONS, type = CommandType.BOOLEAN, description = "Whether API Key rules should be returned. Defaults to false.")
private boolean showPermissions = false;
@Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin},
description = "Lists all API key pairs of users that are accessible by the calling account. Only available for administrators. Defaults to false.")
private boolean listAll = false;
public Long getUserId() {
return userId;
}
public Long getKeyId() {
return keyPairId;
}
public String getApiKeyFilter() {
return apiKeyFilter;
}
public Boolean getShowPermissions() {
return showPermissions;
}
public boolean getListAll() {
return listAll;
}
public long getEntityOwnerId() {
if (getKeyId() != null) {
ApiKeyPair keypair = apiKeyPairService.findById(getKeyId());
if (keypair != null) {
return keypair.getAccountId();
}
} else if (getUserId() != null) {
UserAccount userAccount = _accountService.getUserAccountById(getUserId());
if (userAccount != null) {
return userAccount.getAccountId();
}
}
return Account.ACCOUNT_ID_SYSTEM;
}
public void execute() {
ListResponse<ApiKeyPairResponse> finalResponse = _accountService.listKeys(this);
finalResponse.setObjectName("userkeys");
finalResponse.setResponseName(getCommandName());
setResponseObject(finalResponse);
}
}

View File

@ -1,93 +0,0 @@
// 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.user;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.RegisterUserKeyResponse;
import org.apache.cloudstack.api.response.UserResponse;
import com.cloud.user.Account;
import com.cloud.user.User;
@APICommand(name = "registerUserKeys",
responseObject = RegisterUserKeyResponse.class,
description = "This command allows a user to register for the developer API, returning a secret key and an API key. This request is made through the integration API port, so it is a privileged command and must be made on behalf of a user. It is up to the implementer just how the username and password are entered, and then how that translates to an integration API request. Both secret key and API key should be returned to the user",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
public class RegisterUserKeyCmd extends BaseCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserResponse.class, required = true, description = "User id")
private Long id;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
User user = _entityMgr.findById(User.class, getId());
if (user != null) {
return user.getAccountId();
}
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
@Override
public Long getApiResourceId() {
return id;
}
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.User;
}
@Override
public void execute() {
String[] keys = _accountService.createApiKeyAndSecretKey(this);
RegisterUserKeyResponse response = new RegisterUserKeyResponse();
if (keys != null) {
response.setApiKey(keys[0]);
response.setSecretKey(keys[1]);
}
response.setObjectName("userkeys");
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
}

View File

@ -0,0 +1,209 @@
// 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.user;
import com.cloud.event.EventTypes;
import com.cloud.user.Account;
import com.cloud.user.User;
import org.apache.cloudstack.acl.Rule;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPair;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.commons.lang3.StringUtils;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ApiKeyPairResponse;
import org.apache.cloudstack.api.response.UserResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@APICommand(name = "registerUserKeys",
responseObject = ApiKeyPairResponse.class,
description = "Registers an API key pair (API and secret keys) for a user.",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
public class RegisterUserKeysCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserResponse.class, required = true, description = "ID of the user.")
private Long id;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "API key pair name.")
private String name;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "API key pair description.")
private String description;
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, description = "Start date of the API key pair. " +
ApiConstants.PARAMETER_DESCRIPTION_START_DATE_POSSIBLE_FORMATS)
private Date startDate;
@Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, description = "Expiration date of the API key pair. " +
ApiConstants.PARAMETER_DESCRIPTION_END_DATE_POSSIBLE_FORMATS)
private Date endDate;
@Parameter(name = ApiConstants.RULES, type = CommandType.MAP, description = "The rules of the API key pair. If no rules are informed, " +
"defaults to allowing all account permissions. Otherwise, only the explicitly informed permissions for the key pair will be " +
"considered. Lower indexed rules take precedence over higher. Thus, in the following example: " +
"\"rules[0].rule=deleteUserKeys rules[0].permission=deny rules[1].rule=*UserKey* rules[1].permission=allow\", all rules matching " +
"the expression \"*UserKeys*\" will be allowed, except for \"deleteUserKeys\".")
private Map rules;
public void setUserId(Long userId) {
this.id = userId;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public void setRules(Map rules) {
this.rules = rules;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
public List<Map<String, Object>> getRules() {
List<Map<String, Object>> rulesDetails = new ArrayList<>();
if (rules == null) {
return rulesDetails;
}
for (Object ruleObject : rules.values()) {
HashMap<String, String> detail = (HashMap<String, String>) ruleObject;
Map<String, Object> ruleDetails = new HashMap<>();
String rule = detail.get(ApiConstants.RULE);
if (StringUtils.isEmpty(rule)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Empty rule has been provided in the [rules] parameter.");
}
String permission = detail.get(ApiConstants.PERMISSION);
if (StringUtils.isEmpty(permission)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Rule [%s] has no permission associated with it," +
" please specify if it is either [allow] or [deny].", rule));
}
ruleDetails.put(ApiConstants.RULE, new Rule(rule));
ruleDetails.put(ApiConstants.PERMISSION, roleService.getRolePermission(permission));
String description = detail.get(ApiConstants.DESCRIPTION);
if (StringUtils.isNotEmpty(description)) {
ruleDetails.put(ApiConstants.DESCRIPTION, description);
}
rulesDetails.add(ruleDetails);
}
return rulesDetails;
}
@Override
public long getEntityOwnerId() {
User user = _entityMgr.findById(User.class, getUserId());
List<Long> accessibleUsers = _queryService.searchForAccessibleUsers();
if (user != null && accessibleUsers.stream().anyMatch(u -> u == user.getId())) {
return user.getAccountId();
}
return Account.ACCOUNT_ID_SYSTEM;
}
public Long getUserId() {
return id;
}
@Override
public Long getApiResourceId() {
User user = _entityMgr.findById(User.class, getUserId());
if (user != null) {
return user.getId();
}
return null;
}
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.User;
}
@Override
public void execute() {
ApiKeyPair apiKeyPair = _accountService.createApiKeyAndSecretKey(this);
ApiKeyPairResponse response = new ApiKeyPairResponse();
if (apiKeyPair != null) {
response = _responseGenerator.createKeyPairResponse(apiKeyPair);
}
response.setObjectName("userkeys");
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
@Override
public String getEventType() {
return EventTypes.EVENT_REGISTER_FOR_SECRET_API_KEY;
}
@Override
public String getEventDescription() {
String userUuid = getResourceUuid(ApiConstants.ID);
return String.format("Registering API keypair for user [%s].", userUuid == null ? id : userUuid);
}
@Override
public String getSyncObjType() {
return BaseAsyncCmd.user;
}
@Override
public Long getSyncObjId() {
return getUserId();
}
}

View File

@ -46,8 +46,8 @@ public class UpdateUserCmd extends BaseCmd {
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.USER_API_KEY, type = CommandType.STRING, description = "The API key for the user. Must be specified with userSecretKey")
private String apiKey;
@Parameter(name = ApiConstants.USER_API_KEY, type = CommandType.STRING, description = "Updates the latest API key of the user. Must be specified with usersecretkey")
private String userApiKey;
@Parameter(name = ApiConstants.EMAIL, type = CommandType.STRING, description = "Email")
private String email;
@ -70,8 +70,8 @@ public class UpdateUserCmd extends BaseCmd {
@Parameter(name = ApiConstants.CURRENT_PASSWORD, type = CommandType.STRING, description = "Current password that was being used by the user. You must inform the current password when updating the password.", acceptedOnAdminPort = false)
private String currentPassword;
@Parameter(name = ApiConstants.USER_SECRET_KEY, type = CommandType.STRING, description = "The secret key for the user. Must be specified with userApiKey")
private String secretKey;
@Parameter(name = ApiConstants.USER_SECRET_KEY, type = CommandType.STRING, description = "Updates the latest secret key of the user. Must be specified with userapikey.")
private String userSecretKey;
@Parameter(name = ApiConstants.API_KEY_ACCESS, type = CommandType.STRING, description = "Determines if Api key access for this user is enabled, disabled or inherits the value from its parent, the owning account", since = "4.20.1.0", authorized = {RoleType.Admin})
private String apiKeyAccess;
@ -99,7 +99,7 @@ public class UpdateUserCmd extends BaseCmd {
/////////////////////////////////////////////////////
public String getApiKey() {
return apiKey;
return userApiKey;
}
public String getEmail() {
@ -127,7 +127,7 @@ public class UpdateUserCmd extends BaseCmd {
}
public String getSecretKey() {
return secretKey;
return userSecretKey;
}
public String getApiKeyAccess() {

View File

@ -0,0 +1,109 @@
// 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.vpc;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.network.vpc.VpcOffering;
import org.apache.cloudstack.api.APICommand;
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.VpcOfferingResponse;
import java.util.List;
@APICommand(name = "cloneVPCOffering",
description = "Clones an existing VPC offering. All parameters are copied from the source offering unless explicitly overridden. " +
"Use 'addServices' and 'dropServices' to modify the service list without respecifying everything.",
responseObject = VpcOfferingResponse.class,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false,
since = "4.23.0")
public class CloneVPCOfferingCmd extends CreateVPCOfferingCmd {
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.SOURCE_OFFERING_ID,
type = BaseCmd.CommandType.UUID,
entityType = VpcOfferingResponse.class,
required = true,
description = "The ID of the source VPC offering to clone from")
private Long sourceOfferingId;
@Parameter(name = "addservices",
type = CommandType.LIST,
collectionType = CommandType.STRING,
description = "Services to add to the cloned offering (in addition to source offering services). " +
"If specified along with 'supportedservices', this parameter is ignored.")
private List<String> addServices;
@Parameter(name = "dropservices",
type = CommandType.LIST,
collectionType = CommandType.STRING,
description = "Services to remove from the cloned offering (that exist in source offering). " +
"If specified along with 'supportedservices', this parameter is ignored.")
private List<String> dropServices;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getSourceOfferingId() {
return sourceOfferingId;
}
public List<String> getAddServices() {
return addServices;
}
public List<String> getDropServices() {
return dropServices;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void create() throws ResourceAllocationException {
// Set a temporary entity ID (source offering ID) to prevent NullPointerException
// in ApiServer.queueCommand(). This will be updated in execute() with the actual
// cloned offering ID.
if (sourceOfferingId != null) {
setEntityId(sourceOfferingId);
}
}
@Override
public void execute() {
VpcOffering result = _vpcProvSvc.cloneVPCOffering(this);
if (result != null) {
setEntityId(result.getId());
setEntityUuid(result.getUuid());
VpcOfferingResponse response = _responseGenerator.createVpcOfferingResponse(result);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clone VPC offering");
}
}
}

View File

@ -28,7 +28,6 @@ import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.Network;
import com.cloud.network.VirtualRouterProvider;
import com.cloud.offering.NetworkOffering;
@ -161,6 +160,12 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd {
description = "the routing mode for the VPC offering. Supported types are: Static or Dynamic.")
private String routingMode;
@Parameter(name = ApiConstants.CONSERVE_MODE, type = CommandType.BOOLEAN,
since = "4.23.0",
description = "True if the VPC offering is IP conserve mode enabled, allowing public IPs to be used across multiple VPC tiers. Default value is false")
private Boolean conserveMode;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -179,9 +184,7 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd {
}
public List<String> getSupportedServices() {
if (!isExternalNetworkProvider() && CollectionUtils.isEmpty(supportedServices)) {
throw new InvalidParameterValueException("Supported services needs to be provided");
}
// For external network providers, auto-populate services based on network mode
if (isExternalNetworkProvider()) {
supportedServices = new ArrayList<>(List.of(
Dhcp.getName(),
@ -311,6 +314,10 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd {
return routingMode;
}
public boolean isConserveMode() {
return BooleanUtils.toBoolean(conserveMode);
}
@Override
public void create() throws ResourceAllocationException {
VpcOffering vpcOff = _vpcProvSvc.createVpcOffering(this);

View File

@ -54,7 +54,6 @@ import com.cloud.vm.VirtualMachine;
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements PortForwardingRule {
// ///////////////////////////////////////////////////
// ////////////// API parameters /////////////////////
// ///////////////////////////////////////////////////
@ -278,13 +277,7 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
@Override
public long getNetworkId() {
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
Long ntwkId = null;
if (ip.getAssociatedWithNetworkId() != null) {
ntwkId = ip.getAssociatedWithNetworkId();
} else {
ntwkId = networkId;
}
Long ntwkId = _networkService.getPreferredNetworkIdForPublicIpRuleAssignment(ip, networkId);
if (ntwkId == null) {
throw new InvalidParameterValueException("Unable to create port forwarding rule for the ipAddress id=" + ipAddressId +
" as ip is not associated with any network and no networkId is passed in");

View File

@ -23,6 +23,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.cloud.network.Network;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.APICommand;
@ -72,7 +74,7 @@ public class AssignToLoadBalancerRuleCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID_IP,
type = CommandType.MAP,
description = "VM ID and IP map, vmidipmap[0].vmid=1 vmidipmap[0].vmip=10.1.1.75",
description = "VM ID and IP map, vmidipmap[0].vmid=1 vmidipmap[0].vmip=10.1.1.75. (Optional, for VPC Conserve Mode) Pass vmnetworkid. Example: vmidipmap[0].vmnetworkid=NETWORK_TIER_UUID",
since = "4.4")
private Map vmIdIpMap;
@ -116,8 +118,9 @@ public class AssignToLoadBalancerRuleCmd extends BaseAsyncCmd {
}
public Map<Long, List<String>> getVmIdIpListMap() {
Map<Long, List<String>> vmIdIpsMap = new HashMap<Long, List<String>>();
public Pair<Map<Long, List<String>>, Map<Long, Long>> getVmIdIpListMapAndVmIdNetworkMap() {
Map<Long, List<String>> vmIdIpsMap = new HashMap<>();
Map<Long, Long> vmIdNetworkMap = new HashMap<>();
if (vmIdIpMap != null && !vmIdIpMap.isEmpty()) {
Collection idIpsCollection = vmIdIpMap.values();
Iterator iter = idIpsCollection.iterator();
@ -125,6 +128,7 @@ public class AssignToLoadBalancerRuleCmd extends BaseAsyncCmd {
HashMap<String, String> idIpsMap = (HashMap<String, String>)iter.next();
String vmId = idIpsMap.get("vmid");
String vmIp = idIpsMap.get("vmip");
String vmNetworkUuid = idIpsMap.get("vmnetworkid");
VirtualMachine lbvm = _entityMgr.findByUuid(VirtualMachine.class, vmId);
if (lbvm == null) {
@ -145,25 +149,35 @@ public class AssignToLoadBalancerRuleCmd extends BaseAsyncCmd {
ipsList = new ArrayList<String>();
}
ipsList.add(vmIp);
if (vmNetworkUuid != null) {
Network vmNetwork = _entityMgr.findByUuid(Network.class, vmNetworkUuid);
if (vmNetwork == null) {
throw new InvalidParameterValueException("Unable to find Network ID: " + vmNetworkUuid);
}
vmIdNetworkMap.put(longVmId, vmNetwork.getId());
}
vmIdIpsMap.put(longVmId, ipsList);
}
}
return vmIdIpsMap;
return new Pair<>(vmIdIpsMap, vmIdNetworkMap);
}
@Override
public void execute() {
CallContext.current().setEventDetails("Load balancer ID: " + getResourceUuid(ApiConstants.ID) + " Instances IDs: " + StringUtils.join(getVirtualMachineIds(), ","));
Map<Long, List<String>> vmIdIpsMap = getVmIdIpListMap();
Pair<Map<Long, List<String>>, Map<Long, Long>> mapsPair = getVmIdIpListMapAndVmIdNetworkMap();
Map<Long, List<String>> vmIdIpsMap = mapsPair.first();
Map<Long, Long> vmIdNetworkMap = mapsPair.second();
boolean result = false;
try {
result = _lbService.assignToLoadBalancer(getLoadBalancerId(), virtualMachineIds, vmIdIpsMap, false);
result = _lbService.assignToLoadBalancer(getLoadBalancerId(), virtualMachineIds, vmIdIpsMap, vmIdNetworkMap, false);
}catch (CloudRuntimeException ex) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to assign load balancer rule");
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to assign load balancer rule due to: " + ex.getMessage());
}
if (result) {

View File

@ -0,0 +1,285 @@
// 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.response;
import com.cloud.user.ApiKeyPairState;
import com.google.gson.annotations.SerializedName;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPair;
import org.apache.cloudstack.api.ApiConstants;
import com.cloud.serializer.Param;
import org.apache.cloudstack.api.BaseResponseWithAnnotations;
import org.apache.cloudstack.api.EntityReference;
@EntityReference(value = ApiKeyPair.class)
public class ApiKeyPairResponse extends BaseResponseWithAnnotations {
@SerializedName(ApiConstants.NAME)
@Param(description = "Name of the API key pair")
private String name;
@SerializedName(ApiConstants.API_KEY)
@Param(description = "The API key of the registered user.", isSensitive = true)
private String userApiKey;
@SerializedName(ApiConstants.SECRET_KEY)
@Param(description = "The secret key of the registered user.", isSensitive = true)
private String userSecretKey;
@SerializedName(ApiConstants.USER_ID)
@Param(description = "ID of the user that owns the keypair.")
private String userId;
@SerializedName(ApiConstants.USERNAME)
@Param(description = "Username of the keypair's owner.")
private String username;
@SerializedName(ApiConstants.ID)
@Param(description = "ID of the API key pair.", isSensitive = true)
private String id;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "API key pair description.")
private String description;
@SerializedName(ApiConstants.START_DATE)
@Param(description = "API key pair start date.")
private Date startDate;
@SerializedName(ApiConstants.END_DATE)
@Param(description = "API key pair expiration date.")
private Date endDate;
@SerializedName(ApiConstants.CREATED)
@Param(description = "API key pair creation timestamp.")
private Date created;
@SerializedName(ApiConstants.ACCOUNT_TYPE)
@Param(description = "Account type.")
private String accountType;
@SerializedName(ApiConstants.ACCOUNT_ID)
@Param(description = "Account ID.")
private String accountId;
@SerializedName(ApiConstants.ACCOUNT_NAME)
@Param(description = "Account name.")
private String accountName;
@SerializedName(ApiConstants.ROLE_ID)
@Param(description = "ID of the role.")
private String roleId;
@SerializedName(ApiConstants.ROLE_TYPE)
@Param(description = "Type of the role (Admin, ResourceAdmin, DomainAdmin, User).")
private String roleType;
@SerializedName(ApiConstants.ROLE_NAME)
@Param(description = "Name of the role.")
private String roleName;
@SerializedName(ApiConstants.PERMISSIONS)
@Param(description = "Permissions of the API key pair.")
private List<BaseRolePermissionResponse> permissions;
@SerializedName(ApiConstants.DOMAIN_ID)
@Param(description = "ID of the domain which the account belongs to.")
private String domainId;
@SerializedName(ApiConstants.DOMAIN)
@Param(description = "Name of the domain which the account belongs to.")
private String domainName;
@SerializedName(ApiConstants.DOMAIN_PATH)
@Param(description = "Path of the domain which the account belongs to.")
private String domainPath;
@SerializedName(ApiConstants.STATE)
@Param(description = "State of the API key pair.")
private ApiKeyPairState state;
public String getApiKey() {
return userApiKey;
}
public void setApiKey(String apiKey) {
this.userApiKey = apiKey;
}
public String getSecretKey() {
return userSecretKey;
}
public void setSecretKey(String secretKey) {
this.userSecretKey = secretKey;
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
public String getRoleId() {
return roleId;
}
public void setRoleId(String roleId) {
this.roleId = roleId;
}
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getRoleType() {
return roleType;
}
public void setRoleType(String roleType) {
this.roleType = roleType;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getDomainId() {
return domainId;
}
public void setDomainId(String domainId) {
this.domainId = domainId;
}
public String getDomainName() {
return domainName;
}
public void setDomainName(String domainName) {
this.domainName = domainName;
}
public String getDomainPath() {
return domainPath;
}
public void setDomainPath(String domainPath) {
this.domainPath = domainPath;
}
public ApiKeyPairState getState() {
return state;
}
public void setState(ApiKeyPairState state) {
this.state = state;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public List<BaseRolePermissionResponse> getPermissions() {
return permissions;
}
public void setPermissions(List<BaseRolePermissionResponse> permissions) {
this.permissions = permissions;
}
}

View File

@ -94,6 +94,10 @@ public class FirewallRuleResponse extends BaseResponse {
@Param(description = "The ID of the guest Network the port forwarding rule belongs to")
private String networkId;
@SerializedName(ApiConstants.NETWORK_NAME)
@Param(description = "The Name of the guest Network the port forwarding rule belongs to")
private String networkName;
@SerializedName(ApiConstants.FOR_DISPLAY)
@Param(description = "Is firewall for display to the regular user", since = "4.4", authorized = {RoleType.Admin})
private Boolean forDisplay;
@ -223,6 +227,10 @@ public class FirewallRuleResponse extends BaseResponse {
this.networkId = networkId;
}
public void setNetworkName(String networkName) {
this.networkName = networkName;
}
public void setForDisplay(Boolean forDisplay) {
this.forDisplay = forDisplay;
}

View File

@ -95,12 +95,12 @@ public class UserResponse extends BaseResponse implements SetResourceIconRespons
@Param(description = "The timezone user was created in")
private String timezone;
@SerializedName("apikey")
@SerializedName(ApiConstants.API_KEY)
@Param(description = "The API key of the user", isSensitive = true)
private String apiKey;
@Deprecated
@SerializedName("secretkey")
@SerializedName(ApiConstants.SECRET_KEY)
@Param(description = "The secret key of the user", isSensitive = true)
private String secretKey;

View File

@ -102,6 +102,10 @@ public class VpcOfferingResponse extends BaseResponse {
@Param(description = "The routing mode for the network offering, supported types are Static or Dynamic.")
private String routingMode;
@SerializedName(ApiConstants.CONSERVE_MODE)
@Param(description = "True if the VPC offering is IP conserve mode enabled, allowing public IP services to be used across multiple VPC tiers.", since = "4.23.0")
private Boolean conserveMode;
public void setId(String id) {
this.id = id;
}
@ -201,4 +205,12 @@ public class VpcOfferingResponse extends BaseResponse {
public void setRoutingMode(String routingMode) {
this.routingMode = routingMode;
}
public Boolean getConserveMode() {
return conserveMode;
}
public void setConserveMode(Boolean conserveMode) {
this.conserveMode = conserveMode;
}
}

View File

@ -73,6 +73,10 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
@Param(description = "VPC offering name the VPC is created from", since = "4.13.2")
private String vpcOfferingName;
@SerializedName(ApiConstants.VPC_OFFERING_CONSERVE_MODE)
@Param(description = "true if VPC offering is ip conserve mode enabled", since = "4.23")
private Boolean vpcOfferingConserveMode;
@SerializedName(ApiConstants.CREATED)
@Param(description = "The date this VPC was created")
private Date created;
@ -197,6 +201,10 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
this.displayText = displayText;
}
public void setVpcOfferingConserveMode(Boolean vpcOfferingConserveMode) {
this.vpcOfferingConserveMode = vpcOfferingConserveMode;
}
public void setCreated(final Date created) {
this.created = created;
}

View File

@ -22,6 +22,7 @@ import java.util.Map;
import com.cloud.capacity.Capacity;
import com.cloud.exception.ResourceAllocationException;
import org.apache.cloudstack.api.command.admin.backup.CloneBackupOfferingCmd;
import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd;
import org.apache.cloudstack.api.command.admin.backup.UpdateBackupOfferingCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupCmd;
@ -140,6 +141,12 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
List<Long> getBackupOfferingDomains(final Long offeringId);
/**
* Clone an existing backup offering with updated values
* @param cmd clone backup offering cmd
*/
BackupOffering cloneBackupOffering(final CloneBackupOfferingCmd cmd);
/**
* List backup offerings
* @param ListBackupOfferingsCmd API cmd

View File

@ -145,6 +145,8 @@ public interface QueryService {
ListResponse<UserResponse> searchForUsers(Long domainId, boolean recursive) throws PermissionDeniedException;
List<Long> searchForAccessibleUsers();
ListResponse<EventResponse> searchForEvents(ListEventsCmd cmd);
ListResponse<ResourceTagResponse> listTags(ListTagsCmd cmd);

View File

@ -17,13 +17,46 @@
package org.apache.cloudstack.acl;
import com.cloud.exception.InvalidParameterValueException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.cloudstack.api.APICommand;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
public class RuleTest {
private static List<String> apiNames;
private static List<Rule> apiRules;
private static ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
@BeforeClass
public static void setup() {
provider.addIncludeFilter(new AnnotationTypeFilter(APICommand.class));
Set<BeanDefinition> beanDefinitions = provider.findCandidateComponents("org.apache.cloudstack.api");
apiNames = new ArrayList<>();
apiRules = new ArrayList<>();
for(BeanDefinition bd : beanDefinitions) {
if (bd instanceof AnnotatedBeanDefinition) {
Map<String, Object> annotationAttributeMap = ((AnnotatedBeanDefinition) bd).getMetadata()
.getAnnotationAttributes(APICommand.class.getName());
String apiName = annotationAttributeMap.get("name").toString();
apiNames.add(apiName);
apiRules.add(new Rule(apiName));
}
}
}
@Test
public void testToString() throws Exception {
Rule rule = new Rule("someString");
@ -31,21 +64,89 @@ public class RuleTest {
}
@Test
public void testMatchesEmpty() throws Exception {
Rule rule = new Rule("someString");
Assert.assertFalse(rule.matches(""));
public void ruleMatchesTestNoMatchesOnEmptyString() throws Exception {
String testCmd = "";
List<String> matches = new ArrayList<>();
for (Rule rule : apiRules) {
if (rule.matches(testCmd)) {
matches.add(rule.getRuleString());
}
}
Assert.assertEquals(matches.size(), 0);
}
@Test
public void testMatchesNull() throws Exception {
Rule rule = new Rule("someString");
Assert.assertFalse(rule.matches(null));
public void ruleMatchesTestNoMatchesOnNull() throws Exception {
List<String> matches = new ArrayList<>();
for (Rule rule : apiRules) {
if (rule.matches(null)) {
matches.add(rule.getRuleString());
}
}
Assert.assertTrue(matches.isEmpty());
}
@Test
public void testMatchesSpace() throws Exception {
Rule rule = new Rule("someString");
Assert.assertFalse(rule.matches(" "));
public void ruleMatchesTestNoMatchesOnSpaceCharacter() throws Exception {
String testCmd = " ";
List<String> matches = new ArrayList<>();
for (Rule rule : apiRules) {
if (rule.matches(testCmd)) {
matches.add(rule.getRuleString());
}
}
Assert.assertTrue(matches.isEmpty());
}
@Test
public void ruleMatchesTestWildCardOnEndWorksAsNormalRegex() {
setup();
Pattern regexPattern = Pattern.compile("list.*");
Rule acsRegexRule = new Rule("list*");
List<String> nonMatches = new ArrayList<>();
for (String apiName : apiNames) {
if (acsRegexRule.matches(apiName) != regexPattern.matcher(apiName).matches()) {
nonMatches.add(apiName);
}
}
Assert.assertTrue(nonMatches.isEmpty());
}
@Test
public void ruleMatchesTestWildCardOnMiddleWorksAsNormalRegex() {
setup();
Pattern regexPattern = Pattern.compile("list.*s");
Rule acsRegexRule = new Rule("list*s");
List<String> nonMatches = new ArrayList<>();
for (String apiName : apiNames) {
if (acsRegexRule.matches(apiName) != regexPattern.matcher(apiName).matches()) {
nonMatches.add(apiName);
}
}
Assert.assertTrue(nonMatches.isEmpty());
}
@Test
public void ruleMatchesTestWildCardOnStartWorksAsNormalRegex() {
setup();
Pattern regexPattern = Pattern.compile(".*User");
Rule acsRegexRule = new Rule("*User");
List<String> nonMatches = new ArrayList<>();
for (String apiName : apiNames) {
if (acsRegexRule.matches(apiName) != regexPattern.matcher(apiName).matches()) {
nonMatches.add(apiName);
}
}
Assert.assertTrue(nonMatches.isEmpty());
}
@Test
@ -73,7 +174,25 @@ public class RuleTest {
}
@Test
public void testValidateRuleWithValidData() throws Exception {
public void ruleMatchesTestWildcardOnRuleAndCommand() throws Exception {
Rule rule = new Rule("*");
Assert.assertTrue(rule.matches("list*"));
}
@Test
public void ruleMatchesTestWildcardOnRuleAndCommandNotAllowed() throws Exception {
Rule rule = new Rule("list*");
Assert.assertFalse(rule.matches("*"));
}
@Test
public void ruleMatchesTestWithMultipleStars() throws Exception {
Rule rule = new Rule("list***");
Assert.assertFalse(rule.matches("api"));
}
@Test
public void testRuleToStringWithValidStrings() throws Exception {
for (String rule : Arrays.asList("a", "1", "someApi", "someApi321", "123SomeApi",
"prefix*", "*middle*", "*Suffix",
"*", "**", "f***", "m0nk3yMa**g1c*")) {
@ -82,7 +201,7 @@ public class RuleTest {
}
@Test
public void testValidateRuleWithInvalidData() throws Exception {
public void testRuleToStringWithInvalidStrings() throws Exception {
for (String rule : Arrays.asList(null, "", " ", " ", "\n", "\t", "\r", "\"", "\'",
"^someApi$", "^someApi", "some$", "some-Api;", "some,Api",
"^", "$", "^$", ".*", "\\w+", "r**l3rd0@Kr3", "j@s1n|+|0ȷ",

View File

@ -0,0 +1,301 @@
// 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.backup;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupOffering;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class CloneBackupOfferingCmdTest {
private CloneBackupOfferingCmd cloneBackupOfferingCmd;
@Mock
private BackupManager backupManager;
@Mock
private ResponseGenerator responseGenerator;
@Mock
private BackupOffering mockBackupOffering;
@Mock
private BackupOfferingResponse mockBackupOfferingResponse;
@Before
public void setUp() {
cloneBackupOfferingCmd = new CloneBackupOfferingCmd();
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "backupManager", backupManager);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "_responseGenerator", responseGenerator);
}
@Test
public void testGetSourceOfferingId() {
Long sourceOfferingId = 999L;
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", sourceOfferingId);
assertEquals(sourceOfferingId, cloneBackupOfferingCmd.getSourceOfferingId());
}
@Test
public void testGetName() {
String name = "ClonedBackupOffering";
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", name);
assertEquals(name, cloneBackupOfferingCmd.getName());
}
@Test
public void testGetDescription() {
String description = "Cloned Backup Offering Description";
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "description", description);
assertEquals(description, cloneBackupOfferingCmd.getDescription());
}
@Test
public void testGetZoneId() {
Long zoneId = 123L;
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "zoneId", zoneId);
assertEquals(zoneId, cloneBackupOfferingCmd.getZoneId());
}
@Test
public void testGetExternalId() {
String externalId = "external-backup-123";
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "externalId", externalId);
assertEquals(externalId, cloneBackupOfferingCmd.getExternalId());
}
@Test
public void testGetAllowUserDrivenBackups() {
Boolean allowUserDrivenBackups = true;
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "userDrivenBackups", allowUserDrivenBackups);
assertEquals(allowUserDrivenBackups, cloneBackupOfferingCmd.getUserDrivenBackups());
}
@Test
public void testAllowUserDrivenBackupsDefaultTrue() {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "userDrivenBackups", null);
Boolean result = cloneBackupOfferingCmd.getUserDrivenBackups();
assertTrue(result == null || result);
}
@Test
public void testAllowUserDrivenBackupsFalse() {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "userDrivenBackups", false);
assertEquals(Boolean.FALSE, cloneBackupOfferingCmd.getUserDrivenBackups());
}
@Test
public void testExecuteSuccess() throws Exception {
Long sourceOfferingId = 999L;
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", sourceOfferingId);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", "ClonedBackupOffering");
when(backupManager.cloneBackupOffering(any(CloneBackupOfferingCmd.class))).thenReturn(mockBackupOffering);
when(responseGenerator.createBackupOfferingResponse(mockBackupOffering)).thenReturn(mockBackupOfferingResponse);
cloneBackupOfferingCmd.execute();
assertNotNull(cloneBackupOfferingCmd.getResponseObject());
assertEquals(mockBackupOfferingResponse, cloneBackupOfferingCmd.getResponseObject());
}
@Test
public void testExecuteFailure() throws Exception {
Long sourceOfferingId = 999L;
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(backupManager.cloneBackupOffering(any(CloneBackupOfferingCmd.class))).thenReturn(null);
try {
cloneBackupOfferingCmd.execute();
fail("Expected ServerApiException to be thrown");
} catch (ServerApiException e) {
assertEquals(ApiErrorCode.INTERNAL_ERROR, e.getErrorCode());
assertEquals("Failed to clone backup offering", e.getMessage());
}
}
@Test
public void testExecuteWithInvalidParameterException() throws Exception {
Long sourceOfferingId = 999L;
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(backupManager.cloneBackupOffering(any(CloneBackupOfferingCmd.class)))
.thenThrow(new InvalidParameterValueException("Invalid source offering ID"));
try {
cloneBackupOfferingCmd.execute();
fail("Expected ServerApiException to be thrown");
} catch (ServerApiException e) {
assertEquals(ApiErrorCode.PARAM_ERROR, e.getErrorCode());
assertEquals("Invalid source offering ID", e.getMessage());
}
}
@Test
public void testExecuteWithCloudRuntimeException() throws Exception {
Long sourceOfferingId = 999L;
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(backupManager.cloneBackupOffering(any(CloneBackupOfferingCmd.class)))
.thenThrow(new CloudRuntimeException("Runtime error during clone"));
try {
cloneBackupOfferingCmd.execute();
fail("Expected ServerApiException to be thrown");
} catch (ServerApiException e) {
assertEquals(ApiErrorCode.INTERNAL_ERROR, e.getErrorCode());
assertEquals("Runtime error during clone", e.getMessage());
}
}
@Test
public void testExecuteSuccessWithAllParameters() throws Exception {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", 999L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", "ClonedBackupOffering");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "description", "Test Description");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "zoneId", 123L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "externalId", "ext-123");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "userDrivenBackups", true);
when(backupManager.cloneBackupOffering(any(CloneBackupOfferingCmd.class))).thenReturn(mockBackupOffering);
when(responseGenerator.createBackupOfferingResponse(mockBackupOffering)).thenReturn(mockBackupOfferingResponse);
cloneBackupOfferingCmd.execute();
assertNotNull(cloneBackupOfferingCmd.getResponseObject());
assertEquals(mockBackupOfferingResponse, cloneBackupOfferingCmd.getResponseObject());
}
@Test
public void testCloneWithAllParameters() {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", 999L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", "ClonedBackupOffering");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "description", "Cloned backup offering for testing");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "zoneId", 123L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "externalId", "external-backup-123");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "userDrivenBackups", true);
assertEquals(Long.valueOf(999L), cloneBackupOfferingCmd.getSourceOfferingId());
assertEquals("ClonedBackupOffering", cloneBackupOfferingCmd.getName());
assertEquals("Cloned backup offering for testing", cloneBackupOfferingCmd.getDescription());
assertEquals(Long.valueOf(123L), cloneBackupOfferingCmd.getZoneId());
assertEquals("external-backup-123", cloneBackupOfferingCmd.getExternalId());
assertEquals(Boolean.TRUE, cloneBackupOfferingCmd.getUserDrivenBackups());
}
@Test
public void testCloneWithMinimalParameters() {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", 999L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", "ClonedBackupOffering");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "description", "Description");
assertEquals(Long.valueOf(999L), cloneBackupOfferingCmd.getSourceOfferingId());
assertEquals("ClonedBackupOffering", cloneBackupOfferingCmd.getName());
assertEquals("Description", cloneBackupOfferingCmd.getDescription());
assertNull(cloneBackupOfferingCmd.getZoneId());
assertNull(cloneBackupOfferingCmd.getExternalId());
}
@Test
public void testSourceOfferingIdNullByDefault() {
assertNull(cloneBackupOfferingCmd.getSourceOfferingId());
}
@Test
public void testNameNullByDefault() {
assertNull(cloneBackupOfferingCmd.getName());
}
@Test
public void testDescriptionNullByDefault() {
assertNull(cloneBackupOfferingCmd.getDescription());
}
@Test
public void testZoneIdNullByDefault() {
assertNull(cloneBackupOfferingCmd.getZoneId());
}
@Test
public void testExternalIdNullByDefault() {
assertNull(cloneBackupOfferingCmd.getExternalId());
}
@Test
public void testCloneBackupOfferingInheritingZone() {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", 999L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", "ClonedBackupOffering");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "description", "Clone with inherited zone");
assertEquals(Long.valueOf(999L), cloneBackupOfferingCmd.getSourceOfferingId());
assertNull(cloneBackupOfferingCmd.getZoneId());
}
@Test
public void testCloneBackupOfferingInheritingExternalId() {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", 999L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", "ClonedBackupOffering");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "description", "Clone with inherited external ID");
assertEquals(Long.valueOf(999L), cloneBackupOfferingCmd.getSourceOfferingId());
assertNull(cloneBackupOfferingCmd.getExternalId());
}
@Test
public void testCloneBackupOfferingOverridingZone() {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", 999L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", "ClonedBackupOffering");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "description", "Clone with new zone");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "zoneId", 456L);
assertEquals(Long.valueOf(999L), cloneBackupOfferingCmd.getSourceOfferingId());
assertEquals(Long.valueOf(456L), cloneBackupOfferingCmd.getZoneId());
}
@Test
public void testCloneBackupOfferingDisallowUserDrivenBackups() {
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "sourceOfferingId", 999L);
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "name", "ClonedBackupOffering");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "description", "Clone without user-driven backups");
ReflectionTestUtils.setField(cloneBackupOfferingCmd, "userDrivenBackups", false);
assertEquals(Boolean.FALSE, cloneBackupOfferingCmd.getUserDrivenBackups());
}
}

View File

@ -0,0 +1,324 @@
// 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.network;
import com.cloud.offering.NetworkOffering;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NetworkOfferingResponse;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class CloneNetworkOfferingCmdTest {
private CloneNetworkOfferingCmd cloneNetworkOfferingCmd;
@Mock
private com.cloud.configuration.ConfigurationService configService;
@Mock
private ResponseGenerator responseGenerator;
@Mock
private NetworkOffering mockNetworkOffering;
@Mock
private NetworkOfferingResponse mockNetworkOfferingResponse;
@Before
public void setUp() {
cloneNetworkOfferingCmd = new CloneNetworkOfferingCmd();
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "_configService", configService);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "_responseGenerator", responseGenerator);
}
@Test
public void testGetSourceOfferingId() {
Long sourceOfferingId = 123L;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "sourceOfferingId", sourceOfferingId);
assertEquals(sourceOfferingId, cloneNetworkOfferingCmd.getSourceOfferingId());
}
@Test
public void testGetAddServices() {
List<String> addServices = Arrays.asList("Dhcp", "Dns");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "addServices", addServices);
assertEquals(addServices, cloneNetworkOfferingCmd.getAddServices());
}
@Test
public void testGetDropServices() {
List<String> dropServices = Arrays.asList("Firewall", "Vpn");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "dropServices", dropServices);
assertEquals(dropServices, cloneNetworkOfferingCmd.getDropServices());
}
@Test
public void testGetGuestIpType() {
String guestIpType = "Isolated";
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "guestIptype", guestIpType);
assertEquals(guestIpType, cloneNetworkOfferingCmd.getGuestIpType());
}
@Test
public void testGetTraffictype() {
String trafficType = "GUEST";
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "traffictype", trafficType);
assertEquals(trafficType, cloneNetworkOfferingCmd.getTraffictype());
}
@Test
public void testGetName() {
String name = "ClonedNetworkOffering";
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "networkOfferingName", name);
assertEquals(name, cloneNetworkOfferingCmd.getNetworkOfferingName());
}
@Test
public void testGetDisplayText() {
String displayText = "Cloned Network Offering Display Text";
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "displayText", displayText);
assertEquals(displayText, cloneNetworkOfferingCmd.getDisplayText());
}
@Test
public void testGetDisplayTextDefaultsToName() {
String name = "ClonedNetworkOffering";
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "networkOfferingName", name);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "displayText", null);
assertEquals(name, cloneNetworkOfferingCmd.getDisplayText());
}
@Test
public void testGetAvailability() {
String availability = "Required";
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "availability", availability);
assertEquals(availability, cloneNetworkOfferingCmd.getAvailability());
}
@Test
public void testGetTags() {
String tags = "tag1,tag2,tag3";
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "tags", tags);
assertEquals(tags, cloneNetworkOfferingCmd.getTags());
}
@Test
public void testExecuteSuccess() {
Long sourceOfferingId = 123L;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(configService.cloneNetworkOffering(any(CloneNetworkOfferingCmd.class))).thenReturn(mockNetworkOffering);
when(responseGenerator.createNetworkOfferingResponse(mockNetworkOffering)).thenReturn(mockNetworkOfferingResponse);
cloneNetworkOfferingCmd.execute();
assertNotNull(cloneNetworkOfferingCmd.getResponseObject());
assertEquals(mockNetworkOfferingResponse, cloneNetworkOfferingCmd.getResponseObject());
}
@Test(expected = ServerApiException.class)
public void testExecuteFailure() {
Long sourceOfferingId = 123L;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(configService.cloneNetworkOffering(any(CloneNetworkOfferingCmd.class))).thenReturn(null);
try {
cloneNetworkOfferingCmd.execute();
fail("Expected ServerApiException to be thrown");
} catch (ServerApiException e) {
assertEquals(ApiErrorCode.INTERNAL_ERROR, e.getErrorCode());
assertEquals("Failed to clone network offering", e.getMessage());
throw e;
}
}
@Test
public void testGetConserveMode() {
Boolean conserveMode = true;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "conserveMode", conserveMode);
assertEquals(conserveMode, cloneNetworkOfferingCmd.getConserveMode());
}
@Test
public void testGetSpecifyVlan() {
Boolean specifyVlan = false;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "specifyVlan", specifyVlan);
assertEquals(specifyVlan, cloneNetworkOfferingCmd.getSpecifyVlan());
}
@Test
public void testGetSpecifyIpRanges() {
Boolean specifyIpRanges = true;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "specifyIpRanges", specifyIpRanges);
assertEquals(specifyIpRanges, cloneNetworkOfferingCmd.getSpecifyIpRanges());
}
@Test
public void testGetIsPersistent() {
Boolean isPersistent = true;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "isPersistent", isPersistent);
assertEquals(isPersistent, cloneNetworkOfferingCmd.getIsPersistent());
}
@Test
public void testGetEgressDefaultPolicy() {
Boolean egressDefaultPolicy = false;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "egressDefaultPolicy", egressDefaultPolicy);
assertEquals(egressDefaultPolicy, cloneNetworkOfferingCmd.getEgressDefaultPolicy());
}
@Test
public void testGetServiceOfferingId() {
Long serviceOfferingId = 456L;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "serviceOfferingId", serviceOfferingId);
assertEquals(serviceOfferingId, cloneNetworkOfferingCmd.getServiceOfferingId());
}
@Test
public void testGetForVpc() {
Boolean forVpc = true;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "forVpc", forVpc);
assertEquals(forVpc, cloneNetworkOfferingCmd.getForVpc());
}
@Test
public void testGetMaxConnections() {
Integer maxConnections = 1000;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "maxConnections", maxConnections);
assertEquals(maxConnections, cloneNetworkOfferingCmd.getMaxconnections());
}
@Test
public void testGetNetworkRate() {
Integer networkRate = 200;
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "networkRate", networkRate);
assertEquals(networkRate, cloneNetworkOfferingCmd.getNetworkRate());
}
@Test
public void testGetInternetProtocol() {
String internetProtocol = "ipv4";
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "internetProtocol", internetProtocol);
assertEquals(internetProtocol, cloneNetworkOfferingCmd.getInternetProtocol());
}
@Test
public void testAddServicesNullByDefault() {
assertNull(cloneNetworkOfferingCmd.getAddServices());
}
@Test
public void testDropServicesNullByDefault() {
assertNull(cloneNetworkOfferingCmd.getDropServices());
}
@Test
public void testSupportedServicesParameter() {
List<String> supportedServices = Arrays.asList("Dhcp", "Dns", "SourceNat");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "supportedServices", supportedServices);
assertEquals(supportedServices, cloneNetworkOfferingCmd.getSupportedServices());
}
@Test
public void testServiceProviderListParameter() {
Map<String, HashMap<String, String>> serviceProviderList = new HashMap<>();
HashMap<String, String> dhcpProvider = new HashMap<>();
dhcpProvider.put("service", "Dhcp");
dhcpProvider.put("provider", "VirtualRouter");
HashMap<String, String> dnsProvider = new HashMap<>();
dnsProvider.put("service", "Dns");
dnsProvider.put("provider", "VirtualRouter");
serviceProviderList.put("0", dhcpProvider);
serviceProviderList.put("1", dnsProvider);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "serviceProviderList", serviceProviderList);
Map<String, List<String>> result = cloneNetworkOfferingCmd.getServiceProviders();
assertNotNull(result);
assertEquals(2, result.size());
assertNotNull(result.get("Dhcp"));
assertNotNull(result.get("Dns"));
assertEquals("VirtualRouter", result.get("Dhcp").get(0));
assertEquals("VirtualRouter", result.get("Dns").get(0));
}
@Test
public void testCloneWithAllParameters() {
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "sourceOfferingId", 123L);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "networkOfferingName", "ClonedOffering");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "displayText", "Cloned Offering Display");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "availability", "Optional");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "guestIptype", "Isolated");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "traffictype", "GUEST");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "conserveMode", true);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "specifyVlan", false);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "isPersistent", true);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "egressDefaultPolicy", false);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "networkRate", 200);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "serviceOfferingId", 456L);
assertEquals(Long.valueOf(123L), cloneNetworkOfferingCmd.getSourceOfferingId());
assertEquals("ClonedOffering", cloneNetworkOfferingCmd.getNetworkOfferingName());
assertEquals("Cloned Offering Display", cloneNetworkOfferingCmd.getDisplayText());
assertEquals("Optional", cloneNetworkOfferingCmd.getAvailability());
assertEquals("Isolated", cloneNetworkOfferingCmd.getGuestIpType());
assertEquals("GUEST", cloneNetworkOfferingCmd.getTraffictype());
assertEquals(Boolean.TRUE, cloneNetworkOfferingCmd.getConserveMode());
assertEquals(Boolean.FALSE, cloneNetworkOfferingCmd.getSpecifyVlan());
assertEquals(Boolean.TRUE, cloneNetworkOfferingCmd.getIsPersistent());
assertEquals(Boolean.FALSE, cloneNetworkOfferingCmd.getEgressDefaultPolicy());
assertEquals(Integer.valueOf(200), cloneNetworkOfferingCmd.getNetworkRate());
assertEquals(Long.valueOf(456L), cloneNetworkOfferingCmd.getServiceOfferingId());
}
@Test
public void testCloneWithAddAndDropServices() {
List<String> addServices = Arrays.asList("StaticNat", "PortForwarding");
List<String> dropServices = Arrays.asList("Vpn");
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "sourceOfferingId", 123L);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "addServices", addServices);
ReflectionTestUtils.setField(cloneNetworkOfferingCmd, "dropServices", dropServices);
assertEquals(addServices, cloneNetworkOfferingCmd.getAddServices());
assertEquals(dropServices, cloneNetworkOfferingCmd.getDropServices());
}
}

View File

@ -0,0 +1,669 @@
// 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.offering;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.offering.ServiceOffering;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.vm.lease.VMLeaseManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class CloneServiceOfferingCmdTest {
private CloneServiceOfferingCmd cloneServiceOfferingCmd;
@Mock
private com.cloud.configuration.ConfigurationService configService;
@Mock
private ResponseGenerator responseGenerator;
@Mock
private ServiceOffering mockServiceOffering;
@Mock
private ServiceOfferingResponse mockServiceOfferingResponse;
@Before
public void setUp() {
cloneServiceOfferingCmd = new CloneServiceOfferingCmd();
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "_configService", configService);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "_responseGenerator", responseGenerator);
}
@Test
public void testGetSourceOfferingId() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
assertEquals(sourceOfferingId, cloneServiceOfferingCmd.getSourceOfferingId());
}
@Test
public void testGetServiceOfferingName() {
String name = "ClonedServiceOffering";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", name);
assertEquals(name, cloneServiceOfferingCmd.getServiceOfferingName());
}
@Test
public void testGetDisplayText() {
String displayText = "Cloned Service Offering Display Text";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "displayText", displayText);
assertEquals(displayText, cloneServiceOfferingCmd.getDisplayText());
}
@Test
public void testGetDisplayTextDefaultsToName() {
String name = "ClonedServiceOffering";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", name);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "displayText", null);
assertEquals(name, cloneServiceOfferingCmd.getDisplayText());
}
@Test
public void testGetCpu() {
Integer cpu = 4;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuNumber", cpu);
assertEquals(cpu, cloneServiceOfferingCmd.getCpuNumber());
}
@Test
public void testGetMemory() {
Integer memory = 8192;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "memory", memory);
assertEquals(memory, cloneServiceOfferingCmd.getMemory());
}
@Test
public void testGetCpuSpeed() {
Integer cpuSpeed = 2000;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuSpeed", cpuSpeed);
assertEquals(cpuSpeed, cloneServiceOfferingCmd.getCpuSpeed());
}
@Test
public void testGetOfferHa() {
Boolean offerHa = true;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "offerHa", offerHa);
assertEquals(offerHa, cloneServiceOfferingCmd.isOfferHa());
}
@Test
public void testGetLimitCpuUse() {
Boolean limitCpuUse = false;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "limitCpuUse", limitCpuUse);
assertEquals(limitCpuUse, cloneServiceOfferingCmd.isLimitCpuUse());
}
@Test
public void testGetVolatileVm() {
Boolean volatileVm = true;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "isVolatile", volatileVm);
assertEquals(volatileVm, cloneServiceOfferingCmd.isVolatileVm());
}
@Test
public void testGetStorageType() {
String storageType = "local";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "storageType", storageType);
assertEquals(storageType, cloneServiceOfferingCmd.getStorageType());
}
@Test
public void testGetTags() {
String tags = "ssd,premium,dedicated";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "tags", tags);
assertEquals(tags, cloneServiceOfferingCmd.getTags());
}
@Test
public void testGetHostTag() {
String hostTag = "gpu-enabled";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "hostTag", hostTag);
assertEquals(hostTag, cloneServiceOfferingCmd.getHostTag());
}
@Test
public void testGetNetworkRate() {
Integer networkRate = 1000;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "networkRate", networkRate);
assertEquals(networkRate, cloneServiceOfferingCmd.getNetworkRate());
}
@Test
public void testGetDeploymentPlanner() {
String deploymentPlanner = "UserDispersingPlanner";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "deploymentPlanner", deploymentPlanner);
assertEquals(deploymentPlanner, cloneServiceOfferingCmd.getDeploymentPlanner());
}
@Test
public void testGetDetails() {
Map<String, HashMap<String, String>> details = new HashMap<>();
HashMap<String, String> cpuOvercommit = new HashMap<>();
cpuOvercommit.put("key", "cpuOvercommitRatio");
cpuOvercommit.put("value", "2.0");
HashMap<String, String> memoryOvercommit = new HashMap<>();
memoryOvercommit.put("key", "memoryOvercommitRatio");
memoryOvercommit.put("value", "1.5");
details.put("0", cpuOvercommit);
details.put("1", memoryOvercommit);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "details", details);
Map<String, String> result = cloneServiceOfferingCmd.getDetails();
assertNotNull(result);
assertEquals("2.0", result.get("cpuOvercommitRatio"));
assertEquals("1.5", result.get("memoryOvercommitRatio"));
}
@Test
public void testIsPurgeResources() {
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "purgeResources", true);
assertTrue(cloneServiceOfferingCmd.isPurgeResources());
}
@Test
public void testIsPurgeResourcesFalse() {
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "purgeResources", false);
assertFalse(cloneServiceOfferingCmd.isPurgeResources());
}
@Test
public void testIsPurgeResourcesDefaultFalse() {
assertFalse(cloneServiceOfferingCmd.isPurgeResources());
}
@Test
public void testGetLeaseDuration() {
Integer leaseDuration = 3600;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "leaseDuration", leaseDuration);
assertEquals(leaseDuration, cloneServiceOfferingCmd.getLeaseDuration());
}
@Test
public void testGetLeaseExpiryAction() {
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "leaseExpiryAction", "stop");
assertEquals(VMLeaseManager.ExpiryAction.STOP, cloneServiceOfferingCmd.getLeaseExpiryAction());
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "leaseExpiryAction", "DESTROY");
assertEquals(VMLeaseManager.ExpiryAction.DESTROY, cloneServiceOfferingCmd.getLeaseExpiryAction());
}
@Test(expected = InvalidParameterValueException.class)
public void testGetLeaseExpiryActionInvalidValue() {
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "leaseExpiryAction", "InvalidAction");
cloneServiceOfferingCmd.getLeaseExpiryAction();
}
@Test
public void testGetVgpuProfileId() {
Long vgpuProfileId = 10L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "vgpuProfileId", vgpuProfileId);
assertEquals(vgpuProfileId, cloneServiceOfferingCmd.getVgpuProfileId());
}
@Test
public void testGetGpuCount() {
Integer gpuCount = 2;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "gpuCount", gpuCount);
assertEquals(gpuCount, cloneServiceOfferingCmd.getGpuCount());
}
@Test
public void testGetGpuDisplay() {
Boolean gpuDisplay = true;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "gpuDisplay", gpuDisplay);
assertEquals(gpuDisplay, cloneServiceOfferingCmd.getGpuDisplay());
}
@Test
public void testExecuteSuccess() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
assertEquals(mockServiceOfferingResponse, cloneServiceOfferingCmd.getResponseObject());
}
@Test
public void testExecuteFailure() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(null);
try {
cloneServiceOfferingCmd.execute();
fail("Expected ServerApiException to be thrown");
} catch (ServerApiException e) {
assertEquals(ApiErrorCode.INTERNAL_ERROR, e.getErrorCode());
assertEquals("Failed to clone service offering", e.getMessage());
}
}
@Test
public void testExecuteSuccessWithAllParameters() {
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", 555L);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", "ClonedOffering");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "displayText", "Test Display");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuNumber", 4);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "memory", 8192);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuSpeed", 2000);
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
assertEquals(mockServiceOfferingResponse, cloneServiceOfferingCmd.getResponseObject());
}
@Test
public void testExecuteWithInvalidParameterException() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class)))
.thenThrow(new InvalidParameterValueException("Invalid source offering ID"));
try {
cloneServiceOfferingCmd.execute();
fail("Expected ServerApiException to be thrown");
} catch (ServerApiException e) {
assertEquals(ApiErrorCode.PARAM_ERROR, e.getErrorCode());
assertEquals("Invalid source offering ID", e.getMessage());
}
}
@Test
public void testExecuteWithCloudRuntimeException() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class)))
.thenThrow(new com.cloud.utils.exception.CloudRuntimeException("Runtime error during clone"));
try {
cloneServiceOfferingCmd.execute();
fail("Expected ServerApiException to be thrown");
} catch (ServerApiException e) {
assertEquals(ApiErrorCode.INTERNAL_ERROR, e.getErrorCode());
assertEquals("Runtime error during clone", e.getMessage());
}
}
@Test
public void testExecuteResponseNameIsSet() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
// Verify that response name would be set (actual verification would require accessing the response object's internal state)
}
@Test
public void testCloneWithAllParameters() {
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", 555L);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", "ClonedServiceOffering");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "displayText", "Cloned Service Offering");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuNumber", 4);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "memory", 8192);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuSpeed", 2000);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "offerHa", true);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "limitCpuUse", false);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "isVolatile", true);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "storageType", "local");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "tags", "premium");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "hostTag", "gpu-enabled");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "networkRate", 1000);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "deploymentPlanner", "UserDispersingPlanner");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "purgeResources", true);
assertEquals(Long.valueOf(555L), cloneServiceOfferingCmd.getSourceOfferingId());
assertEquals("ClonedServiceOffering", cloneServiceOfferingCmd.getServiceOfferingName());
assertEquals("Cloned Service Offering", cloneServiceOfferingCmd.getDisplayText());
assertEquals(Integer.valueOf(4), cloneServiceOfferingCmd.getCpuNumber());
assertEquals(Integer.valueOf(8192), cloneServiceOfferingCmd.getMemory());
assertEquals(Integer.valueOf(2000), cloneServiceOfferingCmd.getCpuSpeed());
assertEquals(Boolean.TRUE, cloneServiceOfferingCmd.isOfferHa());
assertEquals(Boolean.FALSE, cloneServiceOfferingCmd.isLimitCpuUse());
assertEquals(Boolean.TRUE, cloneServiceOfferingCmd.isVolatileVm());
assertEquals("local", cloneServiceOfferingCmd.getStorageType());
assertEquals("premium", cloneServiceOfferingCmd.getTags());
assertEquals("gpu-enabled", cloneServiceOfferingCmd.getHostTag());
assertEquals(Integer.valueOf(1000), cloneServiceOfferingCmd.getNetworkRate());
assertEquals("UserDispersingPlanner", cloneServiceOfferingCmd.getDeploymentPlanner());
assertTrue(cloneServiceOfferingCmd.isPurgeResources());
}
@Test
public void testSourceOfferingIdNullByDefault() {
assertNull(cloneServiceOfferingCmd.getSourceOfferingId());
}
@Test
public void testGetSystemVmType() {
String systemVmType = "domainrouter";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "systemVmType", systemVmType);
assertEquals(systemVmType, cloneServiceOfferingCmd.getSystemVmType());
}
@Test
public void testGetBytesReadRate() {
Long bytesReadRate = 1000000L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "bytesReadRate", bytesReadRate);
assertEquals(bytesReadRate, cloneServiceOfferingCmd.getBytesReadRate());
}
@Test
public void testGetBytesWriteRate() {
Long bytesWriteRate = 1000000L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "bytesWriteRate", bytesWriteRate);
assertEquals(bytesWriteRate, cloneServiceOfferingCmd.getBytesWriteRate());
}
@Test
public void testGetIopsReadRate() {
Long iopsReadRate = 1000L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "iopsReadRate", iopsReadRate);
assertEquals(iopsReadRate, cloneServiceOfferingCmd.getIopsReadRate());
}
@Test
public void testGetIopsWriteRate() {
Long iopsWriteRate = 1000L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "iopsWriteRate", iopsWriteRate);
assertEquals(iopsWriteRate, cloneServiceOfferingCmd.getIopsWriteRate());
}
@Test
public void testCloneServiceOfferingWithGpuProfile() {
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", 555L);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", "GPU-Offering-Clone");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "vgpuProfileId", 10L);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "gpuCount", 2);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "gpuDisplay", true);
assertEquals(Long.valueOf(10L), cloneServiceOfferingCmd.getVgpuProfileId());
assertEquals(Integer.valueOf(2), cloneServiceOfferingCmd.getGpuCount());
assertTrue(cloneServiceOfferingCmd.getGpuDisplay());
}
@Test
public void testCloneServiceOfferingWithLease() {
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", 555L);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", "Lease-Offering-Clone");
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "leaseDuration", 7200);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "leaseExpiryAction", "destroy");
assertEquals(Integer.valueOf(7200), cloneServiceOfferingCmd.getLeaseDuration());
assertEquals(VMLeaseManager.ExpiryAction.DESTROY, cloneServiceOfferingCmd.getLeaseExpiryAction());
}
@Test
public void testExecuteWithOverriddenParameters() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
String newName = "ClonedOffering-Override";
String newDisplayText = "Overridden Display Text";
Integer newCpu = 8;
Integer newMemory = 16384;
Integer newCpuSpeed = 3000;
Boolean newOfferHa = true;
Boolean newLimitCpuUse = true;
String newStorageType = "shared";
String newTags = "premium,gpu";
String newHostTag = "compute-optimized";
Integer newNetworkRate = 2000;
String newDeploymentPlanner = "FirstFitPlanner";
Boolean newPurgeResources = true;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", newName);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "displayText", newDisplayText);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuNumber", newCpu);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "memory", newMemory);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuSpeed", newCpuSpeed);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "offerHa", newOfferHa);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "limitCpuUse", newLimitCpuUse);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "storageType", newStorageType);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "tags", newTags);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "hostTag", newHostTag);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "networkRate", newNetworkRate);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "deploymentPlanner", newDeploymentPlanner);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "purgeResources", newPurgeResources);
assertEquals(sourceOfferingId, cloneServiceOfferingCmd.getSourceOfferingId());
assertEquals(newName, cloneServiceOfferingCmd.getServiceOfferingName());
assertEquals(newDisplayText, cloneServiceOfferingCmd.getDisplayText());
assertEquals(newCpu, cloneServiceOfferingCmd.getCpuNumber());
assertEquals(newMemory, cloneServiceOfferingCmd.getMemory());
assertEquals(newCpuSpeed, cloneServiceOfferingCmd.getCpuSpeed());
assertEquals(newOfferHa, cloneServiceOfferingCmd.isOfferHa());
assertEquals(newLimitCpuUse, cloneServiceOfferingCmd.isLimitCpuUse());
assertEquals(newStorageType, cloneServiceOfferingCmd.getStorageType());
assertEquals(newTags, cloneServiceOfferingCmd.getTags());
assertEquals(newHostTag, cloneServiceOfferingCmd.getHostTag());
assertEquals(newNetworkRate, cloneServiceOfferingCmd.getNetworkRate());
assertEquals(newDeploymentPlanner, cloneServiceOfferingCmd.getDeploymentPlanner());
assertTrue(cloneServiceOfferingCmd.isPurgeResources());
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
assertEquals(mockServiceOfferingResponse, cloneServiceOfferingCmd.getResponseObject());
}
@Test
public void testExecuteWithPartialOverrides() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
String newName = "PartialOverride";
Integer newCpu = 6;
Integer newMemory = 12288;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", newName);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "cpuNumber", newCpu);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "memory", newMemory);
assertEquals(newName, cloneServiceOfferingCmd.getServiceOfferingName());
assertEquals(newCpu, cloneServiceOfferingCmd.getCpuNumber());
assertEquals(newMemory, cloneServiceOfferingCmd.getMemory());
assertNull(cloneServiceOfferingCmd.getCpuSpeed());
assertFalse(cloneServiceOfferingCmd.isOfferHa());
assertNull(cloneServiceOfferingCmd.getStorageType());
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
assertEquals(mockServiceOfferingResponse, cloneServiceOfferingCmd.getResponseObject());
}
@Test
public void testExecuteWithGpuOverrides() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
String newName = "GPU-Clone-Override";
Long vgpuProfileId = 15L;
Integer gpuCount = 4;
Boolean gpuDisplay = false;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", newName);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "vgpuProfileId", vgpuProfileId);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "gpuCount", gpuCount);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "gpuDisplay", gpuDisplay);
assertEquals(newName, cloneServiceOfferingCmd.getServiceOfferingName());
assertEquals(vgpuProfileId, cloneServiceOfferingCmd.getVgpuProfileId());
assertEquals(gpuCount, cloneServiceOfferingCmd.getGpuCount());
assertEquals(gpuDisplay, cloneServiceOfferingCmd.getGpuDisplay());
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
assertEquals(mockServiceOfferingResponse, cloneServiceOfferingCmd.getResponseObject());
}
@Test
public void testExecuteWithLeaseOverrides() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
String newName = "Lease-Clone-Override";
Integer leaseDuration = 14400; // 4 hours
String leaseExpiryAction = "stop";
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", newName);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "leaseDuration", leaseDuration);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "leaseExpiryAction", leaseExpiryAction);
assertEquals(newName, cloneServiceOfferingCmd.getServiceOfferingName());
assertEquals(leaseDuration, cloneServiceOfferingCmd.getLeaseDuration());
assertEquals(VMLeaseManager.ExpiryAction.STOP, cloneServiceOfferingCmd.getLeaseExpiryAction());
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
assertEquals(mockServiceOfferingResponse, cloneServiceOfferingCmd.getResponseObject());
}
@Test
public void testExecuteWithStorageOverrides() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
String newName = "Storage-Clone-Override";
Long bytesReadRate = 2000000L;
Long bytesWriteRate = 1500000L;
Long iopsReadRate = 2000L;
Long iopsWriteRate = 1500L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", newName);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "bytesReadRate", bytesReadRate);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "bytesWriteRate", bytesWriteRate);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "iopsReadRate", iopsReadRate);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "iopsWriteRate", iopsWriteRate);
assertEquals(newName, cloneServiceOfferingCmd.getServiceOfferingName());
assertEquals(bytesReadRate, cloneServiceOfferingCmd.getBytesReadRate());
assertEquals(bytesWriteRate, cloneServiceOfferingCmd.getBytesWriteRate());
assertEquals(iopsReadRate, cloneServiceOfferingCmd.getIopsReadRate());
assertEquals(iopsWriteRate, cloneServiceOfferingCmd.getIopsWriteRate());
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
assertEquals(mockServiceOfferingResponse, cloneServiceOfferingCmd.getResponseObject());
}
@Test
public void testExecuteWithDetailsOverride() {
Long sourceOfferingId = 555L;
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "sourceOfferingId", sourceOfferingId);
String newName = "Details-Clone-Override";
Map<String, HashMap<String, String>> details = new HashMap<>();
HashMap<String, String> cpuOvercommit = new HashMap<>();
cpuOvercommit.put("key", "cpuOvercommitRatio");
cpuOvercommit.put("value", "3.0");
HashMap<String, String> memoryOvercommit = new HashMap<>();
memoryOvercommit.put("key", "memoryOvercommitRatio");
memoryOvercommit.put("value", "2.5");
HashMap<String, String> customDetail = new HashMap<>();
customDetail.put("key", "customParameter");
customDetail.put("value", "customValue");
details.put("0", cpuOvercommit);
details.put("1", memoryOvercommit);
details.put("2", customDetail);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "serviceOfferingName", newName);
ReflectionTestUtils.setField(cloneServiceOfferingCmd, "details", details);
assertEquals(newName, cloneServiceOfferingCmd.getServiceOfferingName());
Map<String, String> result = cloneServiceOfferingCmd.getDetails();
assertNotNull(result);
assertEquals("3.0", result.get("cpuOvercommitRatio"));
assertEquals("2.5", result.get("memoryOvercommitRatio"));
assertEquals("customValue", result.get("customParameter"));
when(configService.cloneServiceOffering(any(CloneServiceOfferingCmd.class))).thenReturn(mockServiceOffering);
when(responseGenerator.createServiceOfferingResponse(mockServiceOffering)).thenReturn(mockServiceOfferingResponse);
cloneServiceOfferingCmd.execute();
assertNotNull(cloneServiceOfferingCmd.getResponseObject());
assertEquals(mockServiceOfferingResponse, cloneServiceOfferingCmd.getResponseObject());
}
}

View File

@ -0,0 +1,299 @@
// 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.vpc;
import com.cloud.network.vpc.VpcOffering;
import com.cloud.network.vpc.VpcProvisioningService;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.VpcOfferingResponse;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class CloneVpcOfferingCmdTest {
private CloneVPCOfferingCmd cloneVpcOfferingCmd;
@Mock
private VpcProvisioningService vpcService;
@Mock
private ResponseGenerator responseGenerator;
@Mock
private VpcOffering mockVpcOffering;
@Mock
private VpcOfferingResponse mockVpcOfferingResponse;
@Before
public void setUp() {
cloneVpcOfferingCmd = new CloneVPCOfferingCmd();
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "_vpcProvSvc", vpcService);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "_responseGenerator", responseGenerator);
}
@Test
public void testGetSourceOfferingId() {
Long sourceOfferingId = 789L;
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "sourceOfferingId", sourceOfferingId);
assertEquals(sourceOfferingId, cloneVpcOfferingCmd.getSourceOfferingId());
}
@Test
public void testGetName() {
String name = "ClonedVpcOffering";
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "vpcOfferingName", name);
assertEquals(name, cloneVpcOfferingCmd.getVpcOfferingName());
}
@Test
public void testGetDisplayText() {
String displayText = "Cloned VPC Offering Display Text";
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "displayText", displayText);
assertEquals(displayText, cloneVpcOfferingCmd.getDisplayText());
}
@Test
public void testGetDisplayTextDefaultsToName() {
String name = "ClonedVpcOffering";
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "vpcOfferingName", name);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "displayText", null);
assertEquals(name, cloneVpcOfferingCmd.getDisplayText());
}
@Test
public void testGetServiceOfferingId() {
Long serviceOfferingId = 456L;
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "serviceOfferingId", serviceOfferingId);
assertEquals(serviceOfferingId, cloneVpcOfferingCmd.getServiceOfferingId());
}
@Test
public void testGetInternetProtocol() {
String internetProtocol = "dualstack";
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "internetProtocol", internetProtocol);
assertEquals(internetProtocol, cloneVpcOfferingCmd.getInternetProtocol());
}
@Test
public void testGetProvider() {
String provider = "NSX";
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "provider", provider);
assertEquals(provider, cloneVpcOfferingCmd.getProvider());
}
@Test
public void testGetNetworkMode() {
String networkMode = "ROUTED";
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "networkMode", networkMode);
assertEquals(networkMode, cloneVpcOfferingCmd.getNetworkMode());
}
@Test
public void testGetRoutingMode() {
String routingMode = "dynamic";
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "routingMode", routingMode);
assertEquals(routingMode, cloneVpcOfferingCmd.getRoutingMode());
}
@Test
public void testGetNsxSupportLb() {
Boolean nsxSupportLb = true;
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "nsxSupportsLbService", nsxSupportLb);
assertEquals(nsxSupportLb, cloneVpcOfferingCmd.getNsxSupportsLbService());
}
@Test
public void testGetSpecifyAsnumber() {
Boolean specifyAsnumber = false;
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "specifyAsNumber", specifyAsnumber);
assertEquals(specifyAsnumber, cloneVpcOfferingCmd.getSpecifyAsNumber());
}
@Test
public void testExecuteSuccess() {
Long sourceOfferingId = 789L;
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(vpcService.cloneVPCOffering(any(CloneVPCOfferingCmd.class))).thenReturn(mockVpcOffering);
when(responseGenerator.createVpcOfferingResponse(mockVpcOffering)).thenReturn(mockVpcOfferingResponse);
cloneVpcOfferingCmd.execute();
assertNotNull(cloneVpcOfferingCmd.getResponseObject());
assertEquals(mockVpcOfferingResponse, cloneVpcOfferingCmd.getResponseObject());
}
@Test(expected = ServerApiException.class)
public void testExecuteFailure() {
Long sourceOfferingId = 789L;
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "sourceOfferingId", sourceOfferingId);
when(vpcService.cloneVPCOffering(any(CloneVPCOfferingCmd.class))).thenReturn(null);
try {
cloneVpcOfferingCmd.execute();
fail("Expected ServerApiException to be thrown");
} catch (ServerApiException e) {
assertEquals(ApiErrorCode.INTERNAL_ERROR, e.getErrorCode());
assertEquals("Failed to clone VPC offering", e.getMessage());
throw e;
}
}
@Test
public void testGetSupportedServices() {
List<String> supportedServices = Arrays.asList("Dhcp", "Dns", "SourceNat", "NetworkACL");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "supportedServices", supportedServices);
assertEquals(supportedServices, cloneVpcOfferingCmd.getSupportedServices());
}
@Test
public void testGetServiceProviders() {
Map<String, HashMap<String, String>> serviceProviderList = new HashMap<>();
HashMap<String, String> dhcpProvider = new HashMap<>();
dhcpProvider.put("service", "Dhcp");
dhcpProvider.put("provider", "VpcVirtualRouter");
HashMap<String, String> dnsProvider = new HashMap<>();
dnsProvider.put("service", "Dns");
dnsProvider.put("provider", "VpcVirtualRouter");
HashMap<String, String> aclProvider = new HashMap<>();
aclProvider.put("service", "NetworkACL");
aclProvider.put("provider", "VpcVirtualRouter");
serviceProviderList.put("0", dhcpProvider);
serviceProviderList.put("1", dnsProvider);
serviceProviderList.put("2", aclProvider);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "serviceProviderList", serviceProviderList);
Map<String, List<String>> result = cloneVpcOfferingCmd.getServiceProviders();
assertNotNull(result);
assertEquals(3, result.size());
assertNotNull(result.get("Dhcp"));
assertNotNull(result.get("Dns"));
assertNotNull(result.get("NetworkACL"));
assertEquals("VpcVirtualRouter", result.get("Dhcp").get(0));
assertEquals("VpcVirtualRouter", result.get("Dns").get(0));
assertEquals("VpcVirtualRouter", result.get("NetworkACL").get(0));
}
@Test
public void testGetEnable() {
Boolean enable = true;
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "enable", enable);
assertEquals(enable, cloneVpcOfferingCmd.getEnable());
}
@Test
public void testCloneWithAllParameters() {
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "sourceOfferingId", 789L);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "vpcOfferingName", "ClonedVpcOffering");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "displayText", "Cloned VPC Offering");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "serviceOfferingId", 456L);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "internetProtocol", "ipv4");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "provider", "NSX");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "networkMode", "NATTED");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "routingMode", "static");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "nsxSupportsLbService", true);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "specifyAsNumber", false);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "enable", true);
assertEquals(Long.valueOf(789L), cloneVpcOfferingCmd.getSourceOfferingId());
assertEquals("ClonedVpcOffering", cloneVpcOfferingCmd.getVpcOfferingName());
assertEquals("Cloned VPC Offering", cloneVpcOfferingCmd.getDisplayText());
assertEquals(Long.valueOf(456L), cloneVpcOfferingCmd.getServiceOfferingId());
assertEquals("ipv4", cloneVpcOfferingCmd.getInternetProtocol());
assertEquals("NSX", cloneVpcOfferingCmd.getProvider());
assertEquals("NATTED", cloneVpcOfferingCmd.getNetworkMode());
assertEquals("static", cloneVpcOfferingCmd.getRoutingMode());
assertEquals(Boolean.TRUE, cloneVpcOfferingCmd.getNsxSupportsLbService());
assertEquals(Boolean.FALSE, cloneVpcOfferingCmd.getSpecifyAsNumber());
assertEquals(Boolean.TRUE, cloneVpcOfferingCmd.getEnable());
}
@Test
public void testSourceOfferingIdNullByDefault() {
assertNull(cloneVpcOfferingCmd.getSourceOfferingId());
}
@Test
public void testProviderNullByDefault() {
assertNull(cloneVpcOfferingCmd.getProvider());
}
@Test
public void testServiceCapabilityList() {
Map<String, List<String>> serviceCapabilityList = new HashMap<>();
serviceCapabilityList.put("Connectivity", Arrays.asList("RegionLevelVpc:true", "DistributedRouter:true"));
serviceCapabilityList.put("SourceNat", Arrays.asList("RedundantRouter:true"));
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "serviceCapabilityList", serviceCapabilityList);
Map<String, List<String>> result = cloneVpcOfferingCmd.getServiceCapabilityList();
assertNotNull(result);
assertEquals(serviceCapabilityList, result);
}
@Test
public void testCloneVpcOfferingWithNsxProvider() {
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "sourceOfferingId", 789L);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "provider", "NSX");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "nsxSupportsLbService", true);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "networkMode", "ROUTED");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "routingMode", "dynamic");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "specifyAsNumber", true);
assertEquals("NSX", cloneVpcOfferingCmd.getProvider());
assertEquals(Boolean.TRUE, cloneVpcOfferingCmd.getNsxSupportsLbService());
assertEquals("ROUTED", cloneVpcOfferingCmd.getNetworkMode());
assertEquals("dynamic", cloneVpcOfferingCmd.getRoutingMode());
assertEquals(Boolean.TRUE, cloneVpcOfferingCmd.getSpecifyAsNumber());
}
@Test
public void testCloneVpcOfferingWithNetrisProvider() {
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "sourceOfferingId", 789L);
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "provider", "Netris");
ReflectionTestUtils.setField(cloneVpcOfferingCmd, "networkMode", "NATTED");
assertEquals("Netris", cloneVpcOfferingCmd.getProvider());
assertEquals("NATTED", cloneVpcOfferingCmd.getNetworkMode());
}
}

View File

@ -288,4 +288,6 @@ public interface IpAddressManager {
PublicIpQuarantine updatePublicIpAddressInQuarantine(Long quarantineProcessId, Date endDate);
void updateSourceNatIpAddress(IPAddressVO requestedIp, List<IPAddressVO> userIps) throws Exception;
Long getPreferredNetworkIdForPublicIpRuleAssignment(IpAddress ip, Long networkId);
}

View File

@ -39,7 +39,7 @@ import com.cloud.user.Account;
public interface LoadBalancingRulesManager {
LoadBalancer createPublicLoadBalancer(String xId, String name, String description, int srcPort, int destPort, long sourceIpId, String protocol, String algorithm,
boolean openFirewall, CallContext caller, String lbProtocol, Boolean forDisplay, String cidrList) throws NetworkRuleConflictException;
boolean openFirewall, CallContext caller, String lbProtocol, Boolean forDisplay, String cidrList, Long networkId) throws NetworkRuleConflictException;
boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId);

View File

@ -211,4 +211,9 @@ public interface VpcManager {
void reconfigStaticNatForVpcVr(Long vpcId);
boolean applyStaticRouteForVpcVpnIfNeeded(Long vpcId, boolean updateAllVpn) throws ResourceUnavailableException;
/**
* Returns true if the network is part of a VPC, and the VPC is created from conserve mode enabled VPC offering
*/
boolean isNetworkOnVpcEnabledConserveMode(Network network);
}

View File

@ -91,6 +91,9 @@ public class VpcOfferingVO implements VpcOffering {
@Column(name = "specify_as_number")
private Boolean specifyAsNumber = false;
@Column(name = "conserve_mode")
private boolean conserveMode;
public VpcOfferingVO() {
this.uuid = UUID.randomUUID().toString();
}
@ -242,4 +245,13 @@ public class VpcOfferingVO implements VpcOffering {
public void setSpecifyAsNumber(Boolean specifyAsNumber) {
this.specifyAsNumber = specifyAsNumber;
}
@Override
public boolean isConserveMode() {
return conserveMode;
}
public void setConserveMode(boolean conserveMode) {
this.conserveMode = conserveMode;
}
}

View File

@ -1947,7 +1947,7 @@ public class Upgrade410to420 extends DbUpgradeAbstractImpl {
Map<String, String> detailMap = new HashMap<String, String>();
detailMap.put(ApiConstants.S3_ACCESS_KEY, s3_accesskey);
detailMap.put(ApiConstants.S3_SECRET_KEY, s3_secretkey);
detailMap.put(ApiConstants.SECRET_KEY, s3_secretkey);
detailMap.put(ApiConstants.S3_BUCKET_NAME, s3_bucket);
detailMap.put(ApiConstants.S3_END_POINT, s3_endpoint);
detailMap.put(ApiConstants.S3_HTTPS_FLAG, String.valueOf(s3_https));

View File

@ -36,7 +36,6 @@ import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.lang3.StringUtils;
import com.cloud.utils.db.Encrypt;
import com.cloud.utils.db.GenericDao;
@Entity
@ -69,13 +68,6 @@ public class UserAccountVO implements UserAccount, InternalIdentity {
@Column(name = "state")
private String state;
@Column(name = "api_key")
private String apiKey = null;
@Encrypt
@Column(name = "secret_key")
private String secretKey = null;
@Column(name = GenericDao.CREATED_COLUMN)
private Date created;
@ -203,24 +195,6 @@ public class UserAccountVO implements UserAccount, InternalIdentity {
this.state = state;
}
@Override
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
@Override
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
@Override
public Date getCreated() {
return created;

View File

@ -33,7 +33,6 @@ import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import com.cloud.user.Account.State;
import com.cloud.utils.db.Encrypt;
import com.cloud.utils.db.GenericDao;
import org.apache.commons.lang3.StringUtils;
@ -71,13 +70,6 @@ public class UserVO implements User, Identity, InternalIdentity {
@Enumerated(value = EnumType.STRING)
private State state;
@Column(name = "api_key")
private String apiKey = null;
@Encrypt
@Column(name = "secret_key")
private String secretKey = null;
@Column(name = GenericDao.CREATED_COLUMN)
private Date created;
@ -150,8 +142,6 @@ public class UserVO implements User, Identity, InternalIdentity {
this.setTimezone(user.getTimezone());
this.setUuid(user.getUuid());
this.setSource(user.getSource());
this.setApiKey(user.getApiKey());
this.setSecretKey(user.getSecretKey());
this.setExternalEntity(user.getExternalEntity());
this.setRegistered(user.isRegistered());
this.setRegistrationToken(user.getRegistrationToken());
@ -243,26 +233,6 @@ public class UserVO implements User, Identity, InternalIdentity {
this.state = state;
}
@Override
public String getApiKey() {
return apiKey;
}
@Override
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
@Override
public String getSecretKey() {
return secretKey;
}
@Override
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
@Override
public String getTimezone() {
if (StringUtils.isEmpty(timezone)) {

View File

@ -30,6 +30,4 @@ public interface UserAccountDao extends GenericDao<UserAccountVO, Long> {
List<UserAccountVO> getUserAccountByEmail(String email, Long domainId);
boolean validateUsernameInDomain(String username, Long domainId);
UserAccount getUserByApiKey(String apiKey);
}

View File

@ -19,7 +19,6 @@ package com.cloud.user.dao;
import com.cloud.user.UserAccount;
import com.cloud.user.UserAccountVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import org.springframework.stereotype.Component;
@ -28,14 +27,6 @@ import java.util.List;
@Component
public class UserAccountDaoImpl extends GenericDaoBase<UserAccountVO, Long> implements UserAccountDao {
protected final SearchBuilder<UserAccountVO> userAccountSearch;
public UserAccountDaoImpl() {
userAccountSearch = createSearchBuilder();
userAccountSearch.and("apiKey", userAccountSearch.entity().getApiKey(), SearchCriteria.Op.EQ);
userAccountSearch.done();
}
@Override
public List<UserAccountVO> getAllUsersByNameAndEntity(String username, String entity) {
if (username == null) {
@ -79,12 +70,4 @@ public class UserAccountDaoImpl extends GenericDaoBase<UserAccountVO, Long> impl
}
return false;
}
@Override
public UserAccount getUserByApiKey(String apiKey) {
SearchCriteria<UserAccountVO> sc = userAccountSearch.create();
sc.setParameters("apiKey", apiKey);
return findOneBy(sc);
}
}

View File

@ -37,13 +37,6 @@ public interface UserDao extends GenericDao<UserVO, Long> {
List<UserVO> listByAccount(long accountId);
/**
* Finds a user based on the secret key provided.
* @param secretKey
* @return
*/
UserVO findUserBySecretKey(String secretKey);
/**
* Finds a user based on the registration token provided.
* @param registrationToken

View File

@ -65,10 +65,6 @@ public class UserDaoImpl extends GenericDaoBase<UserVO, Long> implements UserDao
UserIdSearch.and("id", UserIdSearch.entity().getId(), SearchCriteria.Op.EQ);
UserIdSearch.done();
SecretKeySearch = createSearchBuilder();
SecretKeySearch.and("secretKey", SecretKeySearch.entity().getSecretKey(), SearchCriteria.Op.EQ);
SecretKeySearch.done();
RegistrationTokenSearch = createSearchBuilder();
RegistrationTokenSearch.and("registrationToken", RegistrationTokenSearch.entity().getRegistrationToken(), SearchCriteria.Op.EQ);
RegistrationTokenSearch.done();
@ -121,13 +117,6 @@ public class UserDaoImpl extends GenericDaoBase<UserVO, Long> implements UserDao
return listBy(sc);
}
@Override
public UserVO findUserBySecretKey(String secretKey) {
SearchCriteria<UserVO> sc = SecretKeySearch.create();
sc.setParameters("secretKey", secretKey);
return findOneBy(sc);
}
@Override
public UserVO findUserByRegistrationToken(String registrationToken) {
SearchCriteria<UserVO> sc = RegistrationTokenSearch.create();

View File

@ -846,15 +846,18 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
try {
pstmtLegacy = txn.prepareAutoCloseStatement(finalQueryLegacy.toString());
pstmt = txn.prepareAutoCloseStatement(finalQuery.toString());
for (int i = 0; i < resourceIdList.size(); i++) {
pstmtLegacy.setLong(1 + i, resourceIdList.get(i));
pstmt.setLong(1 + i, resourceIdList.get(i));
}
ResultSet rs = pstmtLegacy.executeQuery();
while (rs.next()) {
result.put(rs.getString(1).concat(rs.getString(2)), rs.getLong(3));
}
pstmt = txn.prepareAutoCloseStatement(finalQuery.toString());
for (int i = 0; i < resourceIdList.size(); i++) {
pstmt.setLong(1 + i, resourceIdList.get(i));
}
rs = pstmt.executeQuery();
while (rs.next()) {
result.put(rs.getString(1).concat(rs.getString(2)), rs.getLong(3));

View File

@ -0,0 +1,61 @@
// 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.acl;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "api_keypair_permissions")
public class ApiKeyPairPermissionVO extends RolePermissionBaseVO implements ApiKeyPairPermission {
@Column(name = "api_keypair_id")
private long apiKeyPairId;
@Column(name = "sort_order")
private long sortOrder = 0;
public ApiKeyPairPermissionVO(long apiKeyPairId, String rule, Permission permission, String description) {
super(rule, permission, description);
this.apiKeyPairId = apiKeyPairId;
}
public ApiKeyPairPermissionVO(String rule, Permission permission, String description) {
super(rule, permission, description);
}
public ApiKeyPairPermissionVO() {
}
public long getApiKeyPairId() {
return this.apiKeyPairId;
}
public void setApiKeyPairId(long keyPairId) {
this.apiKeyPairId = keyPairId;
}
public void setSortOrder(long sortOrder) {
this.sortOrder = sortOrder;
}
public long getSortOrder() {
return sortOrder;
}
}

View File

@ -0,0 +1,244 @@
// 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.acl;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.utils.db.Encrypt;
import java.time.Instant;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPair;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
import org.joda.time.DateTime;
@Entity
@Table(name = "api_keypair")
public class ApiKeyPairVO implements ApiKeyPair {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "uuid", nullable = false)
private String uuid = UUID.randomUUID().toString();
@Column(name = "user_id", nullable = false)
private Long userId;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "domain_id", nullable = false)
private Long domainId;
@Column(name = "account_id", nullable = false)
private Long accountId;
@Column(name = "start_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date startDate;
@Column(name = "end_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date endDate;
@Column(name = "created", nullable = false)
@Temporal(value = TemporalType.TIMESTAMP)
private Date created = Date.from(Instant.now());
@Column(name = "description")
private String description = "";
@Column(name = "api_key", nullable = false)
private String apiKey;
@Encrypt
@Column(name = "secret_key", nullable = false)
private String secretKey;
@Column(name = "removed")
@Temporal(value = TemporalType.TIMESTAMP)
private Date removed;
public ApiKeyPairVO() {
}
public ApiKeyPairVO(Long id) {
this.id = id;
}
public ApiKeyPairVO(Long userId, String description, Date startDate, Date endDate,
String apiKey, String secretKey) {
this.userId = userId;
this.description = description;
this.startDate = startDate;
this.endDate = endDate;
this.apiKey = apiKey;
this.secretKey = secretKey;
}
public ApiKeyPairVO(String name, Long userId, String description, Date startDate, Date endDate, Account account) {
this.name = Objects.requireNonNullElseGet(name, () -> userId + " - API key pair");
this.userId = userId;
this.description = description;
this.startDate = startDate;
this.endDate = endDate;
this.domainId = account.getDomainId();
this.accountId = account.getAccountId();
}
public ApiKeyPairVO(Long id, Long userId) {
this.id = id;
this.userId = userId;
}
public void validateDate() {
Date now = DateTime.now().toDate();
Date keypairStart = this.getStartDate();
Date keypairExpiration = this.getEndDate();
if (keypairStart != null && now.compareTo(keypairStart) <= 0) {
throw new InvalidParameterValueException(String.format("API key pair is not valid yet, start date: %s", keypairStart));
}
if (keypairExpiration != null && now.compareTo(keypairExpiration) >= 0) {
throw new InvalidParameterValueException(String.format("API key pair is expired, expiration date: %s", keypairExpiration));
}
}
public boolean hasEndDatePassed() {
Date now = DateTime.now().toDate();
Date keypairExpiration = this.getEndDate();
return keypairExpiration != null && now.compareTo(keypairExpiration) >= 0;
}
public long getId() {
return id;
}
public String getUuid() {
return uuid;
}
public Long getUserId() {
return userId;
}
public Date getStartDate() {
return startDate;
}
public Date getEndDate() {
return endDate;
}
public Date getCreated() {
return created;
}
public String getDescription() {
return description;
}
public String getApiKey() {
return apiKey;
}
public String getSecretKey() {
return secretKey;
}
public Class<?> getEntityType() {
return ApiKeyPair.class;
}
public String getName() {
return name;
}
public Date getRemoved() {
return removed;
}
@Override
public long getDomainId() {
return this.domainId;
}
@Override
public long getAccountId() {
return this.accountId;
}
public void setId(Long id) { this.id = id; }
public void setUuid(String uuid) {
this.uuid = uuid;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public void setDescription(String description) {
this.description = description;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public void setName(String name) {
this.name = name;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public void setCreated(Date created) {
this.created = created;
}
public void setRemoved(Date removed) {
this.removed = removed;
}
}

View File

@ -50,6 +50,12 @@ public class RolePermissionBaseVO implements RolePermissionEntity {
public RolePermissionBaseVO() { this.uuid = UUID.randomUUID().toString(); }
public RolePermissionBaseVO(final String rule, final Permission permission) {
this();
this.rule = rule;
this.permission = permission;
}
public RolePermissionBaseVO(final String rule, final Permission permission, final String description) {
this();
this.rule = rule;

View File

@ -0,0 +1,38 @@
// 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.acl.dao;
import com.cloud.utils.Pair;
import java.util.List;
import org.apache.cloudstack.acl.ApiKeyPairVO;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.api.command.admin.user.ListUserKeysCmd;
public interface ApiKeyPairDao extends GenericDao<ApiKeyPairVO, Long> {
ApiKeyPairVO findBySecretKey(String secretKey);
ApiKeyPairVO findByApiKey(String apiKey);
ApiKeyPairVO findByUuid(String uuid);
Pair<List<ApiKeyPairVO>, Integer> listApiKeysByUserOrApiKeyId(Long userId, Long apiKeyId);
ApiKeyPairVO getLastApiKeyCreatedByUser(Long userId);
Pair<List<ApiKeyPairVO>, Integer> listByUserIdsPaginated(List<Long> userIds, ListUserKeysCmd cmd);
}

View File

@ -0,0 +1,92 @@
// 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.acl.dao;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import java.util.List;
import org.apache.cloudstack.acl.ApiKeyPairVO;
import org.apache.cloudstack.api.command.admin.user.ListUserKeysCmd;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
@Component
public class ApiKeyPairDaoImpl extends GenericDaoBase<ApiKeyPairVO, Long> implements ApiKeyPairDao {
private static final String ID = "id";
private static final String USER_ID = "userId";
private static final String API_KEY = "apiKey";
private static final String SECRET_KEY = "secretKey";
private final SearchBuilder<ApiKeyPairVO> keyPairSearch;
ApiKeyPairDaoImpl() {
super();
keyPairSearch = createSearchBuilder();
keyPairSearch.and(API_KEY, keyPairSearch.entity().getApiKey(), SearchCriteria.Op.EQ);
keyPairSearch.and(SECRET_KEY, keyPairSearch.entity().getSecretKey(), SearchCriteria.Op.EQ);
keyPairSearch.and(ID, keyPairSearch.entity().getId(), SearchCriteria.Op.EQ);
keyPairSearch.and(USER_ID, keyPairSearch.entity().getUserId(), SearchCriteria.Op.IN);
keyPairSearch.done();
}
@Override
public ApiKeyPairVO findByApiKey(String apiKey) {
SearchCriteria<ApiKeyPairVO> sc = keyPairSearch.create();
sc.setParameters(API_KEY, apiKey);
return findOneBy(sc);
}
public ApiKeyPairVO findBySecretKey(String secretKey) {
SearchCriteria<ApiKeyPairVO> sc = keyPairSearch.create();
sc.setParameters(SECRET_KEY, secretKey);
return findOneBy(sc);
}
public Pair<List<ApiKeyPairVO>, Integer> listApiKeysByUserOrApiKeyId(Long userId, Long apiKeyId) {
SearchCriteria<ApiKeyPairVO> sc = keyPairSearch.create();
sc.setParametersIfNotNull(USER_ID, userId);
sc.setParametersIfNotNull(ID, apiKeyId);
final Filter searchFilter = new Filter(100);
return searchAndCount(sc, searchFilter);
}
public ApiKeyPairVO getLastApiKeyCreatedByUser(Long userId) {
final SearchCriteria<ApiKeyPairVO> sc = keyPairSearch.create();
sc.setParametersIfNotNull(USER_ID, userId);
final Filter searchBySorted = new Filter(ApiKeyPairVO.class, ID, false, null, null);
return findOneBy(sc, searchBySorted);
}
public Pair<List<ApiKeyPairVO>, Integer> listByUserIdsPaginated(List<Long> userIds, ListUserKeysCmd cmd) {
Long pageSizeVal = cmd.getPageSizeVal();
Long startIndex = cmd.getStartIndex();
Filter searchFilter = new Filter(ApiKeyPairVO.class, ID, true, startIndex, pageSizeVal);
final SearchCriteria<ApiKeyPairVO> sc = keyPairSearch.create();
sc.setParameters(USER_ID, (Object[]) userIds.toArray(new Long[0]));
Pair<List<ApiKeyPairVO>, Integer> apiKeyPairVOList = searchAndCount(sc, searchFilter);
if (CollectionUtils.isEmpty(apiKeyPairVOList.first())) {
return new Pair<>(List.of(), 0);
}
return apiKeyPairVOList;
}
}

View File

@ -0,0 +1,28 @@
// 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.acl.dao;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.acl.ApiKeyPairPermissionVO;
import java.util.List;
public interface ApiKeyPairPermissionsDao extends GenericDao<ApiKeyPairPermissionVO, Long> {
List<ApiKeyPairPermissionVO> findAllByApiKeyPairId(Long apiKeyPairId);
List<ApiKeyPairPermissionVO> findAllByKeyPairIdSorted(Long apiKeyPairId);
}

View File

@ -0,0 +1,71 @@
// 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.acl.dao;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import java.util.Collections;
import java.util.Objects;
import org.apache.commons.collections.CollectionUtils;
import org.apache.cloudstack.acl.ApiKeyPairPermissionVO;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class ApiKeyPairPermissionsDaoImpl extends GenericDaoBase<ApiKeyPairPermissionVO, Long> implements ApiKeyPairPermissionsDao {
private static final String API_KEY_PAIR_ID = "apiKeyPairId";
private static final String SORT_ORDER = "sortOrder";
private final SearchBuilder<ApiKeyPairPermissionVO> permissionByApiKeyPairIdSearch;
public ApiKeyPairPermissionsDaoImpl() {
super();
permissionByApiKeyPairIdSearch = createSearchBuilder();
permissionByApiKeyPairIdSearch.and(API_KEY_PAIR_ID, permissionByApiKeyPairIdSearch.entity().getApiKeyPairId(), SearchCriteria.Op.EQ);
permissionByApiKeyPairIdSearch.done();
}
public List<ApiKeyPairPermissionVO> findAllByApiKeyPairId(Long apiKeyPairId) {
SearchCriteria<ApiKeyPairPermissionVO> sc = permissionByApiKeyPairIdSearch.create();
sc.setParameters(API_KEY_PAIR_ID, String.valueOf(apiKeyPairId));
return listBy(sc);
}
@Override
public ApiKeyPairPermissionVO persist(final ApiKeyPairPermissionVO item) {
item.setSortOrder(0);
final List<ApiKeyPairPermissionVO> permissionsList = findAllByKeyPairIdSorted(item.getApiKeyPairId());
if (!CollectionUtils.isEmpty(permissionsList)) {
ApiKeyPairPermissionVO lastPermission = permissionsList.get(permissionsList.size() - 1);
item.setSortOrder(lastPermission.getSortOrder() + 1);
}
return super.persist(item);
}
@Override
public List<ApiKeyPairPermissionVO> findAllByKeyPairIdSorted(Long apiKeyPairId) {
final SearchCriteria<ApiKeyPairPermissionVO> sc = permissionByApiKeyPairIdSearch.create();
sc.setParameters(API_KEY_PAIR_ID, apiKeyPairId);
final Filter searchBySorted = new Filter(ApiKeyPairPermissionVO.class, SORT_ORDER, true, null, null);
final List<ApiKeyPairPermissionVO> apiKeyPairPermissionList = listBy(sc, searchBySorted);
return Objects.requireNonNullElse(apiKeyPairPermissionList, Collections.emptyList());
}
}

View File

@ -77,7 +77,7 @@ public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreD
for (ImageStoreDetailVO detail : details) {
String name = detail.getName();
String value = detail.getValue();
if (name.equals(ApiConstants.KEY) || name.equals(ApiConstants.S3_SECRET_KEY)) {
if (name.equals(ApiConstants.KEY) || name.equals(ApiConstants.SECRET_KEY)) {
value = DBEncryptionUtil.decrypt(value);
}
detailsMap.put(name, value);

View File

@ -310,4 +310,6 @@
<bean id="gpuDeviceDaoImpl" class="com.cloud.gpu.dao.GpuDeviceDaoImpl" />
<bean id="vgpuProfileDaoImpl" class="com.cloud.gpu.dao.VgpuProfileDaoImpl" />
<bean id="importVMTaskDaoImpl" class="com.cloud.vm.dao.ImportVMTaskDaoImpl" />
<bean id="apiKeyPairDaoImpl" class="org.apache.cloudstack.acl.dao.ApiKeyPairDaoImpl" />
<bean id="apiKeyPairPermissionsDaoImpl" class="org.apache.cloudstack.acl.dao.ApiKeyPairPermissionsDaoImpl" />
</beans>

View File

@ -34,6 +34,19 @@ CREATE TABLE `cloud`.`backup_offering_details` (
UPDATE `cloud`.`configuration` SET value='random' WHERE name IN ('vm.allocation.algorithm', 'volume.allocation.algorithm') AND value='userconcentratedpod_random';
UPDATE `cloud`.`configuration` SET value='firstfit' WHERE name IN ('vm.allocation.algorithm', 'volume.allocation.algorithm') AND value='userconcentratedpod_firstfit';
-- Create kubernetes_cluster_affinity_group_map table for CKS per-node-type affinity groups
CREATE TABLE IF NOT EXISTS `cloud`.`kubernetes_cluster_affinity_group_map` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`cluster_id` bigint unsigned NOT NULL COMMENT 'kubernetes cluster id',
`node_type` varchar(32) NOT NULL COMMENT 'CONTROL, WORKER, or ETCD',
`affinity_group_id` bigint unsigned NOT NULL COMMENT 'affinity group id',
PRIMARY KEY (`id`),
CONSTRAINT `fk_kubernetes_cluster_ag_map__cluster_id` FOREIGN KEY (`cluster_id`) REFERENCES `kubernetes_cluster`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_kubernetes_cluster_ag_map__ag_id` FOREIGN KEY (`affinity_group_id`) REFERENCES `affinity_group`(`id`) ON DELETE CASCADE,
INDEX `i_kubernetes_cluster_ag_map__cluster_id`(`cluster_id`),
INDEX `i_kubernetes_cluster_ag_map__ag_id`(`affinity_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Create webhook_filter table
DROP TABLE IF EXISTS `cloud`.`webhook_filter`;
CREATE TABLE IF NOT EXISTS `cloud`.`webhook_filter` (
@ -49,3 +62,55 @@ CREATE TABLE IF NOT EXISTS `cloud`.`webhook_filter` (
INDEX `i_webhook_filter__webhook_id`(`webhook_id`),
CONSTRAINT `fk_webhook_filter__webhook_id` FOREIGN KEY(`webhook_id`) REFERENCES `webhook`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- "api_keypair" table for API and secret keys
CREATE TABLE IF NOT EXISTS `cloud`.`api_keypair` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`uuid` varchar(40) UNIQUE NOT NULL,
`name` varchar(255) NOT NULL,
`domain_id` bigint(20) unsigned NOT NULL,
`account_id` bigint(20) unsigned NOT NULL,
`user_id` bigint(20) unsigned NOT NULL,
`start_date` datetime,
`end_date` datetime,
`description` varchar(100),
`api_key` varchar(255) NOT NULL,
`secret_key` varchar(255) NOT NULL,
`created` datetime NOT NULL,
`removed` datetime,
PRIMARY KEY (`id`),
CONSTRAINT `fk_api_keypair__user_id` FOREIGN KEY(`user_id`) REFERENCES `cloud`.`user`(`id`),
CONSTRAINT `fk_api_keypair__account_id` FOREIGN KEY(`account_id`) REFERENCES `cloud`.`account`(`id`),
CONSTRAINT `fk_api_keypair__domain_id` FOREIGN KEY(`domain_id`) REFERENCES `cloud`.`domain`(`id`)
);
-- "api_keypair_permissions" table for API key pairs permissions
CREATE TABLE IF NOT EXISTS `cloud`.`api_keypair_permissions` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`uuid` varchar(40) UNIQUE,
`sort_order` bigint(20) unsigned NOT NULL DEFAULT 0,
`rule` varchar(255) NOT NULL,
`api_keypair_id` bigint(20) unsigned NOT NULL,
`permission` varchar(255) NOT NULL,
`description` varchar(255),
PRIMARY KEY (`id`),
CONSTRAINT `fk_keypair_permissions__api_keypair_id` FOREIGN KEY(`api_keypair_id`) REFERENCES `cloud`.`api_keypair`(`id`)
);
-- Populate "api_keypair" table with existing user API keys
INSERT INTO `cloud`.`api_keypair` (uuid, user_id, domain_id, account_id, api_key, secret_key, created, name)
SELECT UUID(), user.id, account.domain_id, account.id, user.api_key, user.secret_key, NOW(), 'Active key pair'
FROM `cloud`.`user` AS user
JOIN `cloud`.`account` AS account ON user.account_id = account.id
WHERE user.api_key IS NOT NULL AND user.secret_key IS NOT NULL;
-- Drop API keys from user table
ALTER TABLE `cloud`.`user` DROP COLUMN api_key, DROP COLUMN secret_key;
-- Grant access to the "deleteUserKeys" API to the "User", "Domain Admin" and "Resource Admin" roles, similarly to the "registerUserKeys" API
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('User', 'deleteUserKeys', 'ALLOW');
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Domain Admin', 'deleteUserKeys', 'ALLOW');
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Resource Admin', 'deleteUserKeys', 'ALLOW');
-- Add conserve mode for VPC offerings
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','conserve_mode', 'tinyint(1) unsigned NULL DEFAULT 0 COMMENT ''True if the VPC offering is IP conserve mode enabled, allowing public IP services to be used across multiple VPC tiers'' ');

View File

@ -29,8 +29,6 @@ select
user.lastname,
user.email,
user.state,
user.api_key,
user.secret_key,
user.created,
user.removed,
user.timezone,

View File

@ -38,6 +38,7 @@ select
`vpc_offerings`.`sort_key` AS `sort_key`,
`vpc_offerings`.`routing_mode` AS `routing_mode`,
`vpc_offerings`.`specify_as_number` AS `specify_as_number`,
`vpc_offerings`.`conserve_mode` AS `conserve_mode`,
group_concat(distinct `domain`.`id` separator ',') AS `domain_id`,
group_concat(distinct `domain`.`uuid` separator ',') AS `domain_uuid`,
group_concat(distinct `domain`.`name` separator ',') AS `domain_name`,

View File

@ -2604,8 +2604,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
throw new CloudRuntimeException("Destination storage pool with ID " + dataStore.getId() + " was not located.");
}
boolean isSrcAndDestPoolPowerFlexStorage = srcStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex) && destStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex);
if (srcStoragePoolVO.isManaged() && !isSrcAndDestPoolPowerFlexStorage && srcStoragePoolVO.getId() != destStoragePoolVO.getId()) {
if (srcStoragePoolVO.isManaged() && srcStoragePoolVO.getId() != destStoragePoolVO.getId()) {
throw new CloudRuntimeException("Migrating a volume online with KVM from managed storage is not currently supported.");
}

View File

@ -131,7 +131,7 @@ public class ImageStoreHelper {
String key = keyIter.next().toString();
String value = details.get(key);
// encrypt swift key or s3 secret key
if (key.equals(ApiConstants.KEY) || key.equals(ApiConstants.S3_SECRET_KEY)) {
if (key.equals(ApiConstants.KEY) || key.equals(ApiConstants.SECRET_KEY)) {
value = DBEncryptionUtil.encrypt(value);
}
ImageStoreDetailVO detail = new ImageStoreDetailVO(store.getId(), key, value, true);

View File

@ -420,6 +420,14 @@ public class ConfigKey<T> {
return value();
}
/**
* @deprecated
* Still used by some external code, but use {@link ConfigKey#valueInScope(Scope, Long)} instead.
*/
public T valueInDomain(Long domainId) {
return valueInScope(Scope.Domain, domainId);
}
public T valueInScope(Scope scope, Long id) {
if (id == null) {
return value();

View File

@ -17,15 +17,18 @@
package org.apache.cloudstack.acl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.utils.cache.LazyCache;
@ -47,7 +50,7 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
private RoleService roleService;
private List<PluggableService> services;
private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<>();
private LazyCache<Long, Account> accountCache;
private LazyCache<Long, Pair<Role, List<RolePermission>>> rolePermissionsCache;
@ -56,7 +59,7 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
protected DynamicRoleBasedAPIAccessChecker() {
super();
for (RoleType roleType : RoleType.values()) {
annotationRoleBasedApisMap.put(roleType, new HashSet<String>());
annotationRoleBasedApisMap.put(roleType, new HashSet<>());
}
}
@ -67,9 +70,12 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
}
List<RolePermission> allPermissions = roleService.findAllPermissionsBy(role.getId());
List<RolePermissionEntity> allPermissionEntities = allPermissions.stream().map(permission -> (RolePermissionEntity) permission)
.collect(Collectors.toList());
List<String> allowedApis = new ArrayList<>();
for (String api : apiNames) {
if (checkApiPermissionByRole(role, api, allPermissions)) {
if (checkApiPermissionByRole(role, api, allPermissionEntities, false)) {
allowedApis.add(api);
}
}
@ -84,8 +90,8 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
* @param allPermissions list of role permissions for the given role
* @return if the role has the permission for the API
*/
public boolean checkApiPermissionByRole(Role role, String apiName, List<RolePermission> allPermissions) {
for (final RolePermission permission : allPermissions) {
public boolean checkApiPermissionByRole(Role role, String apiName, List<RolePermissionEntity> allPermissions, boolean keyPairOverride) {
for (RolePermissionEntity permission : allPermissions) {
if (!permission.getRule().matches(apiName)) {
continue;
}
@ -94,13 +100,13 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
return false;
}
if (logger.isTraceEnabled()) {
logger.trace(String.format("The API [%s] is allowed for the role %s by the permission [%s].", apiName, role, permission.getRule().toString()));
}
logger.trace("The API [{}] is allowed for the role {} by the permission [{}].", apiName, role, permission.getRule().toString());
return true;
}
return annotationRoleBasedApisMap.get(role.getRoleType()) != null &&
annotationRoleBasedApisMap.get(role.getRoleType()).contains(apiName);
annotationRoleBasedApisMap.get(role.getRoleType()).contains(apiName) &&
!keyPairOverride;
}
protected Account getAccountFromId(long accountId) {
@ -135,49 +141,46 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
}
@Override
public boolean checkAccess(User user, String commandName) throws PermissionDeniedException {
public boolean checkAccess(User user, String commandName, ApiKeyPairPermission ... apiKeyPairPermissions) throws PermissionDeniedException {
if (!isEnabled()) {
return true;
}
Account account = getAccountFromIdUsingCache(user.getAccountId());
if (account == null) {
throw new PermissionDeniedException(String.format("Account for user id [%s] cannot be found", user.getUuid()));
throw new PermissionDeniedException(String.format("Account for user with ID [%s] cannot be found", user.getUuid()));
}
Pair<Role, List<RolePermission>> roleAndPermissions = getRolePermissionsUsingCache(account.getRoleId());
final Role accountRole = roleAndPermissions.first();
if (accountRole == null) {
throw new PermissionDeniedException(String.format("Account role for user id [%s] cannot be found.", user.getUuid()));
}
if (accountRole.getRoleType() == RoleType.Admin && accountRole.getId() == RoleType.Admin.getId()) {
logger.info("Account for user id {} is Root Admin or Domain Admin, all APIs are allowed.", user.getUuid());
return true;
}
List<RolePermission> allPermissions = roleAndPermissions.second();
if (checkApiPermissionByRole(accountRole, commandName, allPermissions)) {
return true;
}
throw new UnavailableCommandException(String.format("The API [%s] does not exist or is not available for the account for user id [%s].", commandName, user.getUuid()));
return checkAccess(account, commandName, apiKeyPairPermissions);
}
public boolean checkAccess(Account account, String commandName) {
@Override
public boolean checkAccess(Account account, String commandName, ApiKeyPairPermission ... apiKeyPairPermissions) {
Pair<Role, List<RolePermission>> roleAndPermissions = getRolePermissionsUsingCache(account.getRoleId());
final Role accountRole = roleAndPermissions.first();
if (accountRole == null) {
throw new PermissionDeniedException(String.format("The account [%s] has role null or unknown.", account));
}
if (accountRole.getRoleType() == RoleType.Admin && accountRole.getId() == RoleType.Admin.getId()) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Account [%s] is Root Admin or Domain Admin, all APIs are allowed.", account));
}
if (accountRole.getRoleType() == RoleType.Admin && accountRole.getId() == RoleType.Admin.getId() && apiKeyPairPermissions.length == 0) {
logger.info("Account [{}] is Root Admin and there aren't any API key pair permissions involved, thus, all APIs are allowed.", account);
return true;
}
List<RolePermission> allPermissions = roleService.findAllPermissionsBy(accountRole.getId());
if (checkApiPermissionByRole(accountRole, commandName, allPermissions)) {
boolean considerKeyPairPermissions = apiKeyPairPermissions.length > 0;
List<RolePermissionEntity> allRules = considerKeyPairPermissions ? Arrays.asList(apiKeyPairPermissions) : new ArrayList<>(roleAndPermissions.second());
if (checkApiPermissionByRole(accountRole, commandName, allRules, considerKeyPairPermissions)) {
return true;
}
throw new UnavailableCommandException(String.format("The API [%s] does not exist or is not available for the account %s.", commandName, account));
throw new UnavailableCommandException(String.format("The API [%s] does not exist or is not available for the account %s.", commandName, account.getAccountName()));
}
@Override
public List<RolePermissionEntity> getImplicitRolePermissions(RoleType roleType) {
return annotationRoleBasedApisMap.get(roleType)
.stream()
.map(implicitApi -> new RolePermissionBaseVO(implicitApi, Permission.ALLOW))
.collect(Collectors.toList());
}
/**

View File

@ -22,6 +22,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.cloud.exception.UnavailableCommandException;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@ -195,4 +197,68 @@ public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase {
List<String> apisReceived = apiAccessCheckerSpy.getApisAllowedToUser(getTestRole(), getTestUser(), apiNames);
Assert.assertEquals(0, apisReceived.size());
}
@Test(expected = UnavailableCommandException.class)
public void checkAccessTestInvalidApiKeyPairPermission() {
final String api = "someDeniedApi";
final ApiKeyPairPermission permission = new ApiKeyPairPermissionVO(1L, api, Permission.DENY, null);
assertFalse(apiAccessCheckerSpy.checkAccess(getTestUser(), api, permission));
}
@Test(expected = UnavailableCommandException.class)
public void checkAccessTestUnrelatedApiKeyPairPermission() {
final String api = "someDeniedApi";
final ApiKeyPairPermission permission = new ApiKeyPairPermissionVO(1L, "apiName", Permission.ALLOW, null);
assertFalse(apiAccessCheckerSpy.checkAccess(getTestUser(), api, permission));
}
@Test
public void checkAccessTestValidApiKeyPairPermission() {
final String api = "someAllowedApi";
final ApiKeyPairPermission permission = new ApiKeyPairPermissionVO(1L, api, Permission.ALLOW, null);
assertTrue(apiAccessCheckerSpy.checkAccess(getTestUser(), api, permission));
}
@Test
public void checkAccessTestValidMultipleApiKeyPermissions() {
final String api = "someAllowedApi";
final ApiKeyPairPermission[] permissions = new ApiKeyPairPermission[]{
new ApiKeyPairPermissionVO(1L, "someDeniedApi", Permission.DENY, null),
new ApiKeyPairPermissionVO(1L, api, Permission.ALLOW, null)
};
assertTrue(apiAccessCheckerSpy.checkAccess(getTestUser(), api, permissions));
}
@Test(expected = UnavailableCommandException.class)
public void checkAccessTestInvalidMultipleApiKeyPermissions() {
final String api = "someDeniedApi";
final ApiKeyPairPermission[] permissions = new ApiKeyPairPermission[]{
new ApiKeyPairPermissionVO(1L, "someAllowedApi", Permission.ALLOW, null),
new ApiKeyPairPermissionVO(1L, api, Permission.DENY, null)
};
assertFalse(apiAccessCheckerSpy.checkAccess(getTestUser(), api, permissions));
}
@Test
public void checkAccessTestValidApiKeyPairPermissionWithNullOverride() {
final String api = "someAllowedApi";
final ApiKeyPairPermission[] emptyPermissionArray = List.of().toArray(new ApiKeyPairPermission[0]);
final RolePermission permission = new RolePermissionVO(1L, api, Permission.ALLOW, null);
Mockito.doReturn(Collections.singletonList(permission)).when(roleServiceMock).findAllPermissionsBy(Mockito.anyLong());
assertTrue(apiAccessCheckerSpy.checkAccess(getTestUser(), api, emptyPermissionArray));
Mockito.verify(roleServiceMock).findAllPermissionsBy(Mockito.anyLong());
}
@Test(expected = UnavailableCommandException.class)
public void checkAccessTestInvalidApiKeyPairPermissionWithNullOverride() {
final String api = "someDeniedApi";
final ApiKeyPairPermission[] emptyPermissionArray = List.of().toArray(new ApiKeyPairPermission[0]);
final RolePermission permission = new RolePermissionVO(1L, api, Permission.DENY, null);
Mockito.doReturn(Collections.singletonList(permission)).when(roleServiceMock).findAllPermissionsBy(Mockito.anyLong());
assertTrue(apiAccessCheckerSpy.checkAccess(getTestUser(), api, emptyPermissionArray));
Mockito.verify(roleServiceMock, Mockito.times(1)).findAllPermissionsBy(Mockito.anyLong());
}
}

View File

@ -23,6 +23,7 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.RolePermissionEntity.Permission;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import org.apache.cloudstack.context.CallContext;
import com.cloud.exception.PermissionDeniedException;
@ -105,7 +106,7 @@ public class ProjectRoleBasedApiAccessChecker extends AdapterBase implements AP
}
@Override
public boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException {
public boolean checkAccess(User user, String apiCommandName, ApiKeyPairPermission... apiKeyPairPermissions) throws PermissionDeniedException {
if (!isEnabled()) {
return true;
}
@ -150,7 +151,7 @@ public class ProjectRoleBasedApiAccessChecker extends AdapterBase implements AP
}
@Override
public boolean checkAccess(Account account, String apiCommandName) throws PermissionDeniedException {
public boolean checkAccess(Account account, String apiCommandName, ApiKeyPairPermission... apiKeyPairPermissions) throws PermissionDeniedException {
return true;
}
@ -182,6 +183,11 @@ public class ProjectRoleBasedApiAccessChecker extends AdapterBase implements AP
return true;
}
@Override
public List<RolePermissionEntity> getImplicitRolePermissions(RoleType roleType) {
return List.of();
}
@Override
public boolean start() {
return super.start();

View File

@ -21,11 +21,13 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.exception.UnavailableCommandException;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import org.apache.cloudstack.api.APICommand;
@ -90,7 +92,7 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIA
}
@Override
public boolean checkAccess(User user, String commandName) throws PermissionDeniedException {
public boolean checkAccess(User user, String commandName, ApiKeyPairPermission... apiKeyPairPermissions) throws PermissionDeniedException {
if (!isEnabled()) {
return true;
}
@ -104,7 +106,7 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIA
}
@Override
public boolean checkAccess(Account account, String commandName) {
public boolean checkAccess(Account account, String commandName, ApiKeyPairPermission... apiKeyPairPermissions) {
if (!isEnabled()) {
return true;
}
@ -163,6 +165,14 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIA
return super.start();
}
@Override
public List<RolePermissionEntity> getImplicitRolePermissions(RoleType roleType) {
return annotationRoleBasedApisMap.get(roleType)
.stream()
.map(implicitApi -> new RolePermissionBaseVO(implicitApi, RolePermissionEntity.Permission.ALLOW))
.collect(Collectors.toList());
}
private void processMapping(Map<String, String> configMap) {
for (Map.Entry<String, String> entry : configMap.entrySet()) {
String apiName = entry.getKey();

View File

@ -39,6 +39,12 @@
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-api-limit-account-based</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -52,7 +52,7 @@ public class ListApisCmd extends BaseCmd {
public void execute() throws ServerApiException {
if (_apiDiscoveryService != null) {
User user = CallContext.current().getCallingUser();
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>)_apiDiscoveryService.listApis(user, name);
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>)_apiDiscoveryService.listApis(user, name, this);
if (response == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Api Discovery plugin was unable to find an api by that name or process any apis");
}

View File

@ -18,6 +18,7 @@ package org.apache.cloudstack.discovery;
import com.cloud.user.Account;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.command.user.discovery.ListApisCmd;
import org.apache.cloudstack.api.response.ListResponse;
import com.cloud.user.User;
@ -28,5 +29,5 @@ import java.util.List;
public interface ApiDiscoveryService extends PluggableService {
List<String> listApiNames(Account account);
ListResponse<? extends BaseResponse> listApis(User user, String apiName);
ListResponse<? extends BaseResponse> listApis(User user, String apiName, ListApisCmd cmd);
}

View File

@ -26,6 +26,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
@ -33,6 +34,8 @@ import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.RolePermissionEntity;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairService;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseAsyncCreateCmd;
@ -44,6 +47,7 @@ import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
import org.apache.cloudstack.api.response.ApiParameterResponse;
import org.apache.cloudstack.api.response.ApiResponseResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.ratelimit.ApiRateLimitService;
import org.apache.cloudstack.resourcedetail.UserDetailVO;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.collections.CollectionUtils;
@ -78,6 +82,9 @@ public class ApiDiscoveryServiceImpl extends ComponentLifecycleBase implements A
@Inject
RoleService roleService;
@Inject
ApiKeyPairService apiKeyPairService;
protected ApiDiscoveryServiceImpl() {
super();
}
@ -257,16 +264,24 @@ public class ApiDiscoveryServiceImpl extends ComponentLifecycleBase implements A
}
@Override
public ListResponse<? extends BaseResponse> listApis(User user, String name) {
public ListResponse<? extends BaseResponse> listApis(User user, String name, ListApisCmd cmd) {
ListResponse<ApiDiscoveryResponse> response = new ListResponse<>();
List<ApiDiscoveryResponse> responseList = new ArrayList<>();
List<String> apisAllowed = new ArrayList<>(s_apiNameDiscoveryResponseMap.keySet());
String apikey = accountService.getAccessingApiKey(cmd);
if (user == null)
return null;
Account account = accountService.getAccount(user.getAccountId());
if (name != null) {
Account account = accountService.getAccount(user.getAccountId());
if (account == null) {
throw new PermissionDeniedException(String.format("The account with id [%s] for user [%s] is null.", user.getAccountId(), user));
}
Role role = roleService.findRole(account.getRoleId());
if (apikey != null) {
responseList = listApisForKeyPair(apikey, name, user, role, apisAllowed);
} else if (name != null) {
if (!s_apiNameDiscoveryResponseMap.containsKey(name))
return null;
@ -281,11 +296,6 @@ public class ApiDiscoveryServiceImpl extends ComponentLifecycleBase implements A
responseList.add(getApiDiscoveryResponseWithAccessibleParams(name, account));
} else {
if (account == null) {
throw new PermissionDeniedException(String.format("The account with id [%s] for user [%s] is null.", user.getAccountId(), user));
}
final Role role = roleService.findRole(account.getRoleId());
if (role == null || role.getId() < 1L) {
throw new PermissionDeniedException(String.format("The account [%s] has role null or unknown.",
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(account, "accountName", "uuid")));
@ -343,6 +353,44 @@ public class ApiDiscoveryServiceImpl extends ComponentLifecycleBase implements A
return cmdList;
}
protected List<ApiDiscoveryResponse> listApisForKeyPair(String apiKey, String apiName, User user, Role role, List<String> apisAllowed) {
List<RolePermissionEntity> keyPairPermissions = accountService.getAllKeypairPermissions(apiKey);
List<String> filteredApis = new ArrayList<>();
if (apiName != null && isApiAllowedForKey(keyPairPermissions, apiName)) {
filteredApis = List.of(apiName);
} else {
for (String api : apisAllowed) {
if (isApiAllowedForKey(keyPairPermissions, api)) {
filteredApis.add(api);
}
}
}
checkRateLimit(user, role, filteredApis);
return filteredApis.stream().map(api -> s_apiNameDiscoveryResponseMap.get(api)).collect(Collectors.toList());
}
protected boolean isApiAllowedForKey(List<RolePermissionEntity> rolePermissionEntities, String apiName) {
for (RolePermissionEntity rolePermissionEntity : rolePermissionEntities) {
if (!rolePermissionEntity.getRule().matches(apiName)) {
continue;
}
return rolePermissionEntity.getPermission().equals(RolePermissionEntity.Permission.ALLOW);
}
return false;
}
private void checkRateLimit(User user, Role role, List<String> apiNames) {
for (APIChecker apiChecker : _apiAccessCheckers) {
if (!(apiChecker instanceof ApiRateLimitService)) {
continue;
}
apiChecker.getApisAllowedToUser(role, user, apiNames);
return;
}
}
public List<APIChecker> getApiAccessCheckers() {
return _apiAccessCheckers;
}

View File

@ -99,7 +99,7 @@ public class ApiDiscoveryTest {
@Test (expected = PermissionDeniedException.class)
public void listApisTestThrowPermissionDeniedExceptionOnAccountNull() throws PermissionDeniedException {
Mockito.when(accountServiceMock.getAccount(Mockito.anyLong())).thenReturn(null);
discoveryServiceSpy.listApis(getTestUser(), null);
discoveryServiceSpy.listApis(getTestUser(), null, null);
}
@Test (expected = PermissionDeniedException.class)
@ -107,7 +107,7 @@ public class ApiDiscoveryTest {
Mockito.when(accountServiceMock.getAccount(Mockito.anyLong())).thenReturn(getNormalAccount());
Mockito.when(roleServiceMock.findRole(Mockito.anyLong())).thenReturn(null);
discoveryServiceSpy.listApis(getTestUser(), null);
discoveryServiceSpy.listApis(getTestUser(), null, null);
}
@Test (expected = PermissionDeniedException.class)
@ -117,7 +117,7 @@ public class ApiDiscoveryTest {
Mockito.when(accountServiceMock.getAccount(Mockito.anyLong())).thenReturn(getNormalAccount());
Mockito.when(roleServiceMock.findRole(Mockito.anyLong())).thenReturn(unknownRoleVO);
discoveryServiceSpy.listApis(getTestUser(), null);
discoveryServiceSpy.listApis(getTestUser(), null, null);
}
@Test
@ -128,7 +128,7 @@ public class ApiDiscoveryTest {
Mockito.when(accountServiceMock.getAccount(Mockito.anyLong())).thenReturn(adminAccountVO);
Mockito.when(roleServiceMock.findRole(Mockito.anyLong())).thenReturn(adminRoleVO);
discoveryServiceSpy.listApis(getTestUser(), null);
discoveryServiceSpy.listApis(getTestUser(), null, null);
Mockito.verify(apiCheckerMock, Mockito.times(0)).getApisAllowedToUser(any(Role.class), any(User.class), anyList());
}
@ -140,7 +140,7 @@ public class ApiDiscoveryTest {
Mockito.when(accountServiceMock.getAccount(Mockito.anyLong())).thenReturn(getNormalAccount());
Mockito.when(roleServiceMock.findRole(Mockito.anyLong())).thenReturn(userRoleVO);
discoveryServiceSpy.listApis(getTestUser(), null);
discoveryServiceSpy.listApis(getTestUser(), null, null);
Mockito.verify(apiCheckerMock, Mockito.times(1)).getApisAllowedToUser(any(Role.class), any(User.class), anyList());
}
@ -153,7 +153,7 @@ public class ApiDiscoveryTest {
Mockito.when(mockUserAccount.getDetails()).thenReturn(userDetails);
Mockito.when(accountServiceMock.getAccount(Mockito.anyLong())).thenReturn(getNormalAccount());
Mockito.when(roleServiceMock.findRole(Mockito.anyLong())).thenReturn(userRoleVO);
discoveryServiceSpy.listApis(getTestUser(), null);
discoveryServiceSpy.listApis(getTestUser(), null, null);
Mockito.verify(apiCheckerMock, Mockito.times(1)).getApisAllowedToUser(any(Role.class), any(User.class), anyList());
}
@ -166,7 +166,7 @@ public class ApiDiscoveryTest {
Mockito.when(accountServiceMock.getAccount(Mockito.anyLong())).thenReturn(getNormalAccount());
Mockito.when(roleServiceMock.findRole(Mockito.anyLong())).thenReturn(userRoleVO);
Mockito.when(apiNameDiscoveryResponseMapMock.get(Mockito.anyString())).thenReturn(Mockito.mock(ApiDiscoveryResponse.class));
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>) discoveryServiceSpy.listApis(getTestUser(), null);
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>) discoveryServiceSpy.listApis(getTestUser(), null, null);
Assert.assertEquals(4, response.getResponses().size());
}
}

View File

@ -27,6 +27,9 @@ import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RolePermissionEntity;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.apikeypair.ApiKeyPairPermission;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.springframework.stereotype.Component;
@ -161,17 +164,17 @@ public class ApiRateLimitServiceImpl extends AdapterBase implements APIChecker,
}
@Override
public boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException {
public boolean checkAccess(User user, String apiCommandName, ApiKeyPairPermission ... apiKeyPairPermissions) throws PermissionDeniedException {
if (!isEnabled()) {
return true;
}
Account account = _accountService.getAccount(user.getAccountId());
return checkAccess(account, apiCommandName);
return checkAccess(account, apiCommandName, apiKeyPairPermissions);
}
@Override
public boolean checkAccess(Account account, String commandName) {
public boolean checkAccess(Account account, String commandName, ApiKeyPairPermission ... apiKeyPairPermissions) {
Long accountId = account.getAccountId();
if (_accountService.isRootAdmin(accountId)) {
logger.info(String.format("Account [%s] is Root Admin, in this case, API limit does not apply.",
@ -207,6 +210,11 @@ public class ApiRateLimitServiceImpl extends AdapterBase implements APIChecker,
return true;
}
@Override
public List<RolePermissionEntity> getImplicitRolePermissions(RoleType roleType) {
return List.of();
}
@Override
public boolean isEnabled() {
if (!enabled) {

View File

@ -252,7 +252,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
}
public boolean isUserAllowedToSeeActivationRules(User user) {
List<ApiDiscoveryResponse> apiList = (List<ApiDiscoveryResponse>) apiDiscoveryService.listApis(user, null).getResponses();
List<ApiDiscoveryResponse> apiList = (List<ApiDiscoveryResponse>) apiDiscoveryService.listApis(user, null, null).getResponses();
return apiList.stream().anyMatch(response -> StringUtils.equalsAny(response.getName(), "quotaTariffCreate", "quotaTariffUpdate"));
}

View File

@ -652,7 +652,7 @@ public class QuotaResponseBuilderImplTest extends TestCase {
ListResponse<ApiDiscoveryResponse> responseList = new ListResponse<>();
responseList.setResponses(cmdList);
Mockito.doReturn(responseList).when(discoveryServiceMock).listApis(userMock, null);
Mockito.doReturn(responseList).when(discoveryServiceMock).listApis(userMock, null, null);
assertTrue(quotaResponseBuilderSpy.isUserAllowedToSeeActivationRules(userMock));
}
@ -668,7 +668,7 @@ public class QuotaResponseBuilderImplTest extends TestCase {
ListResponse<ApiDiscoveryResponse> responseList = new ListResponse<>();
responseList.setResponses(cmdList);
Mockito.doReturn(responseList).when(discoveryServiceMock).listApis(userMock, null);
Mockito.doReturn(responseList).when(discoveryServiceMock).listApis(userMock, null, null);
assertTrue(quotaResponseBuilderSpy.isUserAllowedToSeeActivationRules(userMock));
}
@ -684,7 +684,7 @@ public class QuotaResponseBuilderImplTest extends TestCase {
ListResponse<ApiDiscoveryResponse> responseList = new ListResponse<>();
responseList.setResponses(cmdList);
Mockito.doReturn(responseList).when(discoveryServiceMock).listApis(userMock, null);
Mockito.doReturn(responseList).when(discoveryServiceMock).listApis(userMock, null, null);
assertFalse(quotaResponseBuilderSpy.isUserAllowedToSeeActivationRules(userMock));
}

View File

@ -263,9 +263,8 @@ public class BaremetalVlanManagerImpl extends ManagerBase implements BaremetalVl
user.setSource(User.Source.UNKNOWN);
user = userDao.persist(user);
String[] keys = acntMgr.createApiKeyAndSecretKey(user.getId());
user.setApiKey(keys[0]);
user.setSecretKey(keys[1]);
acntMgr.createApiKeyAndSecretKey(user.getId());
userDao.update(user.getId(), user);
return true;
}

Some files were not shown because too many files have changed in this diff Show More