Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,6 @@
import java.util.Map;

import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.command.user.UserCmd;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.api.response.SnapshotResponse;
import org.apache.cloudstack.api.response.TemplateResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.api.response.ProjectResponse;

import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
Expand All @@ -41,13 +29,23 @@
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject.ResponseView;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.user.UserCmd;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.SnapshotResponse;
import org.apache.cloudstack.api.response.TemplateResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.projects.Project;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Volume;
import com.cloud.template.VirtualMachineTemplate;
Expand Down Expand Up @@ -139,6 +137,19 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd implements UserCmd {
@Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "the zone for the template. Can be specified with snapshot only", since = "4.19.0")
private Long zoneId;

@Parameter(name = ApiConstants.DOMAIN_ID,
type = CommandType.UUID,
entityType = DomainResponse.class,
description = "an optional domainId. If the account parameter is used, domainId must also be used.",
since = "4.19.0")
private Long domainId;

@Parameter(name = ApiConstants.ACCOUNT,
type = CommandType.STRING,
description = "an optional accountName. Must be used with domainId.",
since = "4.19.0")
private String accountName;

// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
Expand Down Expand Up @@ -217,6 +228,14 @@ public Long getZoneId() {
return zoneId;
}

public Long getDomainId() {
return domainId;
}

public String getAccountName() {
return accountName;
}

// ///////////////////////////////////////////////////
// ///////////// API Implementation///////////////////
// ///////////////////////////////////////////////////
Expand All @@ -232,47 +251,12 @@ public static String getResultObjectName() {

@Override
public long getEntityOwnerId() {
Long volumeId = getVolumeId();
Long snapshotId = getSnapshotId();
Account callingAccount = CallContext.current().getCallingAccount();
if (volumeId != null) {
Volume volume = _entityMgr.findById(Volume.class, volumeId);
if (volume != null) {
_accountService.checkAccess(callingAccount, SecurityChecker.AccessType.UseEntry, false, volume);
} else {
throw new InvalidParameterValueException("Unable to find volume by id=" + volumeId);
}
} else {
Snapshot snapshot = _entityMgr.findById(Snapshot.class, snapshotId);
if (snapshot != null) {
_accountService.checkAccess(callingAccount, SecurityChecker.AccessType.UseEntry, false, snapshot);
} else {
throw new InvalidParameterValueException("Unable to find snapshot by id=" + snapshotId);
}
}

if(projectId != null){
final Project project = _projectService.getProject(projectId);
if (project != null) {
if (project.getState() == Project.State.Active) {
Account projectAccount= _accountService.getAccount(project.getProjectAccountId());
_accountService.checkAccess(callingAccount, SecurityChecker.AccessType.UseEntry, false, projectAccount);
return project.getProjectAccountId();
} else {
final PermissionDeniedException ex =
new PermissionDeniedException("Can't add resources to the project with specified projectId in state=" + project.getState() +
" as it's no longer active");
ex.addProxyObject(project.getUuid(), "projectId");
throw ex;
}
} else {
throw new InvalidParameterValueException("Unable to find project by id");
}
}

return callingAccount.getId();
ensureAccessCheck(callingAccount);
return findAccountIdToUse(callingAccount);
}


@Override
public String getEventType() {
return EventTypes.EVENT_TEMPLATE_CREATE;
Expand Down Expand Up @@ -330,4 +314,47 @@ public void execute() {
}

}

/***
* Performs access check on volume and snapshot for given account
* @param account
*/
private void ensureAccessCheck(Account account) {
if (volumeId != null) {
Volume volume = _entityMgr.findById(Volume.class, volumeId);
if (volume != null) {
_accountService.checkAccess(account, SecurityChecker.AccessType.UseEntry, false, volume);
} else {
throw new InvalidParameterValueException("Unable to find volume by id=" + volumeId);
}
} else {
Snapshot snapshot = _entityMgr.findById(Snapshot.class, snapshotId);
if (snapshot != null) {
_accountService.checkAccess(account, SecurityChecker.AccessType.UseEntry, false, snapshot);
} else {
throw new InvalidParameterValueException("Unable to find snapshot by id=" + snapshotId);
}
}
}

/***
* Find accountId based on accountName and domainId or projectId
* if not found, return callingAccountId for further use
* @param callingAccount
* @return accountId
*/
private Long findAccountIdToUse(Account callingAccount) {
Long accountIdToUse = null;
try {
accountIdToUse = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
} catch (InvalidParameterValueException | PermissionDeniedException ex) {
if (s_logger.isDebugEnabled()) {
s_logger.debug(String.format("An exception occurred while finalizing account id with accountName, domainId and projectId" +
"using callingAccountId=%s", callingAccount.getUuid()), ex);
}
s_logger.warn("Unable to find accountId associated with accountName=" + accountName + " and domainId="
+ domainId + " or projectId=" + projectId + ", using callingAccountId=" + callingAccount.getUuid());
}
return accountIdToUse != null ? accountIdToUse : callingAccount.getAccountId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,20 @@ public void testGetZoneId() {
ReflectionTestUtils.setField(cmd, "zoneId", id);
Assert.assertEquals(id, cmd.getZoneId());
}

@Test
public void testDomainId() {
final CreateTemplateCmd cmd = new CreateTemplateCmd();
Long id = 2L;
ReflectionTestUtils.setField(cmd, "domainId", id);
Assert.assertEquals(id, cmd.getDomainId());
}

@Test
public void testGetAccountName() {
final CreateTemplateCmd cmd = new CreateTemplateCmd();
String accountName = "user1";
ReflectionTestUtils.setField(cmd, "accountName", accountName);
Assert.assertEquals(accountName, cmd.getAccountName());
}
}