diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java old mode 100644 new mode 100755 index 908318fba6c..0137190a0d4 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -81,6 +81,7 @@ public class ApiConstants { public static final String IP_LIMIT = "iplimit"; public static final String IP_TOTAL = "iptotal"; public static final String IS_CLEANUP_REQUIRED = "iscleanuprequired"; + public static final String IS_EXTRACTABLE = "isextractable"; public static final String IS_FEATURED = "isfeatured"; public static final String IS_PUBLIC = "ispublic"; public static final String IS_READY = "isready"; diff --git a/api/src/com/cloud/api/commands/RegisterTemplateCmd.java b/api/src/com/cloud/api/commands/RegisterTemplateCmd.java index added37a6d8..4a7075e3073 100755 --- a/api/src/com/cloud/api/commands/RegisterTemplateCmd.java +++ b/api/src/com/cloud/api/commands/RegisterTemplateCmd.java @@ -67,6 +67,9 @@ public class RegisterTemplateCmd extends BaseCmd { @Parameter(name=ApiConstants.PASSWORD_ENABLED, type=CommandType.BOOLEAN, description="true if the template supports the password reset feature; default is false") private Boolean passwordEnabled; + + @Parameter(name=ApiConstants.IS_EXTRACTABLE, type=CommandType.BOOLEAN, description="true if the template or its derivatives are extractable; default is true") + private Boolean extractable; @Parameter(name=ApiConstants.REQUIRES_HVM, type=CommandType.BOOLEAN, description="true if this template requires HVM") private Boolean requiresHvm; @@ -123,6 +126,10 @@ public class RegisterTemplateCmd extends BaseCmd { return passwordEnabled; } + public Boolean isExtractable() { + return extractable; + } + public Boolean getRequiresHvm() { return requiresHvm; } diff --git a/api/src/com/cloud/api/response/TemplateResponse.java b/api/src/com/cloud/api/response/TemplateResponse.java index 86a8912c6b4..d66756eefc1 100755 --- a/api/src/com/cloud/api/response/TemplateResponse.java +++ b/api/src/com/cloud/api/response/TemplateResponse.java @@ -104,6 +104,9 @@ public class TemplateResponse extends BaseResponse { @SerializedName("domainid") @Param(description="the ID of the domain to which the template belongs") private Long domainId; + @SerializedName("isextractable") @Param(description="true if the template is extractable, false otherwise") + private Boolean extractable; + public Long getZoneId() { return zoneId; } @@ -311,4 +314,12 @@ public class TemplateResponse extends BaseResponse { public void setDomainId(long domainId) { this.domainId = domainId; } + + public Boolean isExtractable() { + return extractable; + } + + public void setExtractable(Boolean extractable) { + this.extractable = extractable; + } } diff --git a/api/src/com/cloud/template/VirtualMachineTemplate.java b/api/src/com/cloud/template/VirtualMachineTemplate.java index 658a9ee5dff..d94a4a21cea 100755 --- a/api/src/com/cloud/template/VirtualMachineTemplate.java +++ b/api/src/com/cloud/template/VirtualMachineTemplate.java @@ -49,6 +49,8 @@ public interface VirtualMachineTemplate extends ControlledEntity { */ boolean isPublicTemplate(); + boolean isExtractable(); + /** * @return name */ diff --git a/core/src/com/cloud/storage/VMTemplateVO.java b/core/src/com/cloud/storage/VMTemplateVO.java old mode 100644 new mode 100755 index 7219689e16b..39ec9196ced --- a/core/src/com/cloud/storage/VMTemplateVO.java +++ b/core/src/com/cloud/storage/VMTemplateVO.java @@ -106,7 +106,9 @@ public class VMTemplateVO implements VirtualMachineTemplate { @Column(name="hypervisor_type") private String hypervisorType; - + @Column(name="extractable") + private boolean extractable = true; + public String getUniqueName() { return uniqueName; } @@ -121,8 +123,8 @@ public class VMTemplateVO implements VirtualMachineTemplate { /** * Proper constructor for a new vm template. */ - public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { - this(id, generateUniqueName(id, accountId, name), name, format, isPublic, featured, type, url, null, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType); + public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { + this(id, generateUniqueName(id, accountId, name), name, format, isPublic, featured, isExtractable, type, url, null, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType); } public VMTemplateVO(Long id, String uniqueName, String name, ImageFormat format, boolean isPublic, boolean featured, TemplateType type, String url, Date created, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { @@ -144,10 +146,33 @@ public class VMTemplateVO implements VirtualMachineTemplate { this.guestOSId = guestOSId; this.bootable = bootable; this.hypervisorType = hyperType.toString(); - } - - @Override - public boolean getEnablePassword() { + } + + // Has an extra attribute - isExtractable + public VMTemplateVO(Long id, String uniqueName, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, Date created, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { + this.id = id; + this.name = name; + this.publicTemplate = isPublic; + this.featured = featured; + this.extractable = isExtractable; + this.templateType = type; + this.url = url; + this.requiresHvm = requiresHvm; + this.bits = bits; + this.accountId = accountId; + this.checksum = cksum; + this.uniqueName = uniqueName; + this.displayText = displayText; + this.enablePassword = enablePassword; + this.format = format; + this.created = created; + this.guestOSId = guestOSId; + this.bootable = bootable; + this.hypervisorType = hyperType.toString(); + } + + @Override + public boolean getEnablePassword() { return enablePassword; } @@ -310,6 +335,15 @@ public class VMTemplateVO implements VirtualMachineTemplate { hypervisorType = hyperType.toString(); } + @Override + public boolean isExtractable() { + return extractable; + } + + public void setExtractable(boolean extractable) { + this.extractable = extractable; + } + @Override public long getDomainId() { return -1; diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index f69203a8717..fefbb14e534 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -1571,6 +1571,7 @@ public class ApiResponseHelper implements ResponseGenerator { templateResponse.setName(template.getName()); templateResponse.setDisplayText(template.getDisplayText()); templateResponse.setPublic(template.isPublicTemplate()); + templateResponse.setExtractable(template.isExtractable()); templateResponse.setCrossZones(template.isCrossZones()); VMTemplateHostVO isoHostRef = ApiDBUtils.findTemplateHostRef(template.getId(), zone.getId()); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 1afc8713865..136dc669cfb 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -5197,6 +5197,12 @@ public class ManagementServerImpl implements ManagementServer { throw new PermissionDeniedException("Invalid state of the volume with ID: " + volumeId + ". It should be either detached or the VM should be in stopped state."); } + VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); + boolean isExtractable = template != null && template.isExtractable() && !(template.getTemplateType()== Storage.TemplateType.SYSTEM || template.getTemplateType()== Storage.TemplateType.BUILTIN); + if( !isExtractable ){ + throw new PermissionDeniedException("The volume:" +volumeId+ " is not allowed to be extracted"); + } + Upload.Mode extractMode; if( mode == null || (!mode.equals(Upload.Mode.FTP_UPLOAD.toString()) && !mode.equals(Upload.Mode.HTTP_DOWNLOAD.toString())) ){ throw new ServerApiException(BaseCmd.PARAM_ERROR, "Please specify a valid extract Mode "); diff --git a/server/src/com/cloud/template/TemplateManager.java b/server/src/com/cloud/template/TemplateManager.java index e2467d3bdb7..3eeee5ca657 100755 --- a/server/src/com/cloud/template/TemplateManager.java +++ b/server/src/com/cloud/template/TemplateManager.java @@ -46,6 +46,7 @@ public interface TemplateManager { * @param displayText user readable name. * @param isPublic is this a public template? * @param featured is this template featured? + * @param isExtractable is this template extractable? * @param format which image format is the template. * @param fs what is the file system on the template * @param url url to download the template from. @@ -57,7 +58,7 @@ public interface TemplateManager { * @param bootable true if this template will represent a bootable ISO * @return id of the template created. */ - Long createInZone(long zoneId, long userId, String displayText, boolean isPublic, boolean featured, ImageFormat format, TemplateType type, URI url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable); + Long createInZone(long zoneId, long userId, String displayText, boolean isPublic, boolean featured, boolean isExtractable, ImageFormat format, TemplateType type, URI url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable); /** * Prepares a template for vm creation for a certain storage pool. diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 68925c0efc9..edf9ac0f31d 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -248,7 +248,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe throw new ServerApiException(BaseCmd.PARAM_ERROR, "File:// type urls are currently unsupported"); } - return createTemplateOrIso(userId, accountId, zoneId, name, displayText, isPublic.booleanValue(), featured.booleanValue(), ImageFormat.ISO.toString(), null, url, null, true, 64 /*bits*/, false, guestOSId, bootable, HypervisorType.None); + return createTemplateOrIso(userId, accountId, zoneId, name, displayText, isPublic.booleanValue(), featured.booleanValue(), true, ImageFormat.ISO.toString(), null, url, null, true, 64 /*bits*/, false, guestOSId, bootable, HypervisorType.None); } @Override @@ -264,6 +264,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe String url = cmd.getUrl(); Boolean isPublic = cmd.isPublic(); Boolean featured = cmd.isFeatured(); + Boolean isExtractable = cmd.isExtractable(); String format = cmd.getFormat(); Long guestOSId = cmd.getOsTypeId(); Long zoneId = cmd.getZoneId(); @@ -286,6 +287,9 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe if (isPublic == null) { isPublic = Boolean.FALSE; } + if(isExtractable == null){ + isExtractable = Boolean.TRUE; + } if (zoneId.longValue() == -1) { zoneId = null; @@ -353,11 +357,11 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe userId = Long.valueOf(1); } - return createTemplateOrIso(userId, accountId, zoneId, name, displayText, isPublic, featured, format, "ext3", url, null, requiresHVM, bits, passwordEnabled, guestOSId, true, hypervisorType); + return createTemplateOrIso(userId, accountId, zoneId, name, displayText, isPublic, featured, isExtractable, format, "ext3", url, null, requiresHVM, bits, passwordEnabled, guestOSId, true, hypervisorType); } - private VMTemplateVO createTemplateOrIso(long userId, Long accountId, Long zoneId, String name, String displayText, boolean isPublic, boolean featured, String format, String diskType, String url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hypervisorType) throws IllegalArgumentException, ResourceAllocationException { + private VMTemplateVO createTemplateOrIso(long userId, Long accountId, Long zoneId, String name, String displayText, boolean isPublic, boolean featured, boolean isExtractable, String format, String diskType, String url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hypervisorType) throws IllegalArgumentException, ResourceAllocationException { try { if (name.length() > 32) @@ -419,13 +423,13 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe throw new IllegalArgumentException("Cannot use reserved names for templates"); } - return create(userId, accountId, zoneId, name, displayText, isPublic, featured, imgfmt, null, uri, chksum, requiresHvm, bits, enablePassword, guestOSId, bootable, hypervisorType); + return create(userId, accountId, zoneId, name, displayText, isPublic, featured, isExtractable, imgfmt, null, uri, chksum, requiresHvm, bits, enablePassword, guestOSId, bootable, hypervisorType); } catch (URISyntaxException e) { throw new IllegalArgumentException("Invalid URL " + url); } } - private VMTemplateVO create(long userId, long accountId, Long zoneId, String name, String displayText, boolean isPublic, boolean featured, ImageFormat format, TemplateType type, URI url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { + private VMTemplateVO create(long userId, long accountId, Long zoneId, String name, String displayText, boolean isPublic, boolean featured, boolean isExtractable, ImageFormat format, TemplateType type, URI url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { Long id = _tmpltDao.getNextInSequence(Long.class, "id"); AccountVO account = _accountDao.findById(accountId); @@ -433,7 +437,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe throw new IllegalArgumentException("Only admins can create templates in all zones"); } - VMTemplateVO template = new VMTemplateVO(id, name, format, isPublic, featured, type, url.toString(), requiresHvm, bits, accountId, chksum, displayText, enablePassword, guestOSId, bootable, hyperType); + VMTemplateVO template = new VMTemplateVO(id, name, format, isPublic, featured, isExtractable, type, url.toString(), requiresHvm, bits, accountId, chksum, displayText, enablePassword, guestOSId, bootable, hyperType); if (zoneId == null) { List dcs = _dcDao.listAllIncludingRemoved(); @@ -500,7 +504,9 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe throw new InvalidParameterValueException("Unsupported format, could not extract the template"); } } - + if(!template.isExtractable()){ + throw new PermissionDeniedException("The "+ desc + " is not allowed to be extracted" ); + } if (_dcDao.findById(zoneId) == null) { throw new IllegalArgumentException("Please specify a valid zone."); } @@ -1117,7 +1123,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe @Override public Long createInZone(long zoneId, long userId, String displayText, - boolean isPublic, boolean featured, ImageFormat format, + boolean isPublic, boolean featured, boolean isExtractable, ImageFormat format, TemplateType type, URI url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable) { Long id = _tmpltDao.getNextInSequence(Long.class, "id"); @@ -1125,7 +1131,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe UserVO user = _userDao.findById(userId); long accountId = user.getAccountId(); - VMTemplateVO template = new VMTemplateVO(id, displayText, format, isPublic, featured, type, url.toString(), requiresHvm, bits, accountId, chksum, displayText, enablePassword, guestOSId, bootable, null); + VMTemplateVO template = new VMTemplateVO(id, displayText, format, isPublic, featured, isExtractable, type, url.toString(), requiresHvm, bits, accountId, chksum, displayText, enablePassword, guestOSId, bootable, null); Long templateId = _tmpltDao.addTemplateToZone(template, zoneId); UserAccount userAccount = _userAccountDao.findById(userId); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 838df1b1e33..a623c532994 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -63,6 +63,7 @@ import com.cloud.agent.api.VmStatsEntry; import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; +import com.cloud.api.ApiDBUtils; import com.cloud.api.BaseCmd; import com.cloud.api.ServerApiException; import com.cloud.api.commands.AttachVolumeCmd; @@ -2472,6 +2473,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, VirtualM Long nextTemplateId = _templateDao.getNextInSequence(Long.class, "id"); String description = cmd.getDisplayText(); + VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); + boolean isExtractable = template != null && template.isExtractable() && !(template.getTemplateType()== Storage.TemplateType.SYSTEM || template.getTemplateType()== Storage.TemplateType.BUILTIN); privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, @@ -2479,6 +2482,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, VirtualM ImageFormat.RAW, isPublic, featured, + isExtractable, null, null, null, @@ -2490,7 +2494,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, VirtualM passwordEnabledValue, guestOS.getId(), true, - hyperType); + hyperType); // FIXME: scheduled events should get saved when the command is actually scheduled, not when it starts executing, need another callback // for when the command is scheduled? Could this fit into the setup / execute / response lifecycle? Right after setup you would diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 0aa7000398c..16e849826c8 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -579,6 +579,7 @@ CREATE TABLE `cloud`.`vm_template` ( `bootable` int(1) unsigned NOT NULL default 1 COMMENT 'true if this template represents a bootable ISO', `prepopulate` int(1) unsigned NOT NULL default 0 COMMENT 'prepopulate this template to primary storage', `cross_zones` int(1) unsigned NOT NULL default 0 COMMENT 'Make this template available in all zones', + `extractable` int(1) unsigned NOT NULL default 1 COMMENT 'Is this template extractable', `hypervisor_type` varchar(255) COMMENT 'hypervisor that the template is belonged to', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;