diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index b30097ced42..bad53390612 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -252,4 +252,5 @@ public class ApiConstants { public static final String FOR_LOAD_BALANCING = "forloadbalancing"; public static final String KEYBOARD="keyboard"; public static final String OPEN_FIREWALL="openfirewall"; + public static final String TEMPLATE_TAG = "templatetag"; } diff --git a/api/src/com/cloud/api/commands/CreateTemplateCmd.java b/api/src/com/cloud/api/commands/CreateTemplateCmd.java index 090a993ac46..02d702fcf8d 100755 --- a/api/src/com/cloud/api/commands/CreateTemplateCmd.java +++ b/api/src/com/cloud/api/commands/CreateTemplateCmd.java @@ -41,7 +41,7 @@ import com.cloud.user.UserContext; @Implementation(responseObject = StoragePoolResponse.class, description = "Creates a template of a virtual machine. " + "The virtual machine must be in a STOPPED state. " + "A template created from this command is automatically designated as a private template visible to the account that created it.") -public class CreateTemplateCmd extends BaseAsyncCreateCmd { + public class CreateTemplateCmd extends BaseAsyncCreateCmd { public static final Logger s_logger = Logger.getLogger(CreateTemplateCmd.class.getName()); private static final String s_name = "createtemplateresponse"; @@ -78,14 +78,15 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.LONG, description = "the ID of the disk volume the template is being created from. Either this parameter, or snapshotId has to be passed in") private Long volumeId; - + @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.LONG, description="Optional, VM ID. If this presents, it is going to create a baremetal template for VM this ID refers to. This is only for VM whose hypervisor type is BareMetal") private Long vmId; - + @Parameter(name=ApiConstants.URL, type=CommandType.STRING, description="Optional, only for baremetal hypervisor. The directory name where template stored on CIFS server") private String url; - - + + @Parameter(name=ApiConstants.TEMPLATE_TAG, type=CommandType.STRING, description="the tag for this template.") + private String templateTag; // /////////////////////////////////////////////////// // ///////////////// Accessors /////////////////////// @@ -130,14 +131,18 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd { public Long getVolumeId() { return volumeId; } - + public Long getVmId() { - return vmId; + return vmId; } public String getUrl() { return url; } + + public String getTemplateTag() { + return templateTag; + } // /////////////////////////////////////////////////// // ///////////// API Implementation/////////////////// // /////////////////////////////////////////////////// @@ -187,26 +192,26 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd { } private boolean isBareMetal() { - return (this.getVmId() != null && this.getUrl() != null); + return (this.getVmId() != null && this.getUrl() != null); } - + @Override public void create() throws ResourceAllocationException { - if (isBareMetal()) { - _bareMetalVmService.createPrivateTemplateRecord(this); - /*Baremetal creates template record after taking image proceeded, use vmId as entity id here*/ - this.setEntityId(vmId); - } else { - VirtualMachineTemplate template = null; - template = _userVmService.createPrivateTemplateRecord(this); + if (isBareMetal()) { + _bareMetalVmService.createPrivateTemplateRecord(this); + /*Baremetal creates template record after taking image proceeded, use vmId as entity id here*/ + this.setEntityId(vmId); + } else { + VirtualMachineTemplate template = null; + template = _userVmService.createPrivateTemplateRecord(this); - if (template != null) { - this.setEntityId(template.getId()); - } else { - throw new ServerApiException(BaseCmd.INTERNAL_ERROR, - "Failed to create a template"); - } - } + if (template != null) { + this.setEntityId(template.getId()); + } else { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, + "Failed to create a template"); + } + } } @Override @@ -218,13 +223,13 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd { } else { template = _userVmService.createPrivateTemplate(this); } - + if (template != null){ List templateResponses; if (isBareMetal()) { - templateResponses = _responseGenerator.createTemplateResponses(template.getId(), vmId); + templateResponses = _responseGenerator.createTemplateResponses(template.getId(), vmId); } else { - templateResponses = _responseGenerator.createTemplateResponses(template.getId(), snapshotId, volumeId, false); + templateResponses = _responseGenerator.createTemplateResponses(template.getId(), snapshotId, volumeId, false); } TemplateResponse response = new TemplateResponse(); if (templateResponses != null && !templateResponses.isEmpty()) { @@ -235,6 +240,6 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd { } else { throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to create private template"); } - + } } diff --git a/api/src/com/cloud/api/commands/RegisterTemplateCmd.java b/api/src/com/cloud/api/commands/RegisterTemplateCmd.java index 7a039cc0af3..a150488f325 100755 --- a/api/src/com/cloud/api/commands/RegisterTemplateCmd.java +++ b/api/src/com/cloud/api/commands/RegisterTemplateCmd.java @@ -38,7 +38,7 @@ import com.cloud.user.UserContext; @Implementation(description="Registers an existing template into the Cloud.com cloud. ", responseObject=TemplateResponse.class) public class RegisterTemplateCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(RegisterTemplateCmd.class.getName()); + public static final Logger s_logger = Logger.getLogger(RegisterTemplateCmd.class.getName()); private static final String s_name = "registertemplateresponse"; @@ -72,7 +72,7 @@ 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 false") private Boolean extractable; @@ -84,16 +84,19 @@ public class RegisterTemplateCmd extends BaseCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required=true, description="the ID of the zone the template is to be hosted on") private Long zoneId; - + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="an optional domainId. If the account parameter is used, domainId must also be used.") private Long domainId; @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="an optional accountName. Must be used with domainId.") private String accountName; - + @Parameter(name=ApiConstants.CHECKSUM, type=CommandType.STRING, description="the MD5 checksum value of this template") private String checksum; + @Parameter(name=ApiConstants.TEMPLATE_TAG, type=CommandType.STRING, description="the tag for this template.") + private String templateTag; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -135,9 +138,9 @@ public class RegisterTemplateCmd extends BaseCmd { } public Boolean isExtractable() { - return extractable; + return extractable; } - + public Boolean getRequiresHvm() { return requiresHvm; } @@ -151,30 +154,33 @@ public class RegisterTemplateCmd extends BaseCmd { } public Long getDomainId() { - return domainId; - } + return domainId; + } + + public String getAccountName() { + return accountName; + } - public String getAccountName() { - return accountName; - } - public String getChecksum() { return checksum; } - + + public String getTemplateTag() { + return templateTag; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// - @Override + @Override public String getCommandName() { return s_name; } - - public AsyncJob.Type getInstanceType() { - return AsyncJob.Type.Template; + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Template; } - + @Override public long getEntityOwnerId() { Account account = UserContext.current().getCaller(); @@ -188,9 +194,9 @@ public class RegisterTemplateCmd extends BaseCmd { } } } - + return account.getId(); - } + } @Override public void execute() throws ResourceAllocationException{ diff --git a/api/src/com/cloud/api/response/TemplateResponse.java b/api/src/com/cloud/api/response/TemplateResponse.java index 2c97f64cabd..29e07557b7a 100755 --- a/api/src/com/cloud/api/response/TemplateResponse.java +++ b/api/src/com/cloud/api/response/TemplateResponse.java @@ -80,7 +80,7 @@ public class TemplateResponse extends BaseResponse { @SerializedName("zonename") @Param(description="the name of the zone for this template") private String zoneName; - + @SerializedName("status") @Param(description="the status of the template") private String status; @@ -107,23 +107,27 @@ public class TemplateResponse extends BaseResponse { @SerializedName("isextractable") @Param(description="true if the template is extractable, false otherwise") private Boolean extractable; - + @SerializedName("checksum") @Param(description="checksum of the template") private String checksum; - + @SerializedName("sourcetemplateid") @Param(description="the template ID of the parent template if present") private Long sourcetemplateId; - + @SerializedName(ApiConstants.HOST_ID) @Param(description="the ID of the secondary storage host for the template") private Long hostId; @SerializedName("hostname") @Param(description="the name of the secondary storage host for the template") private String hostName; - + + @SerializedName("templatetag") @Param(description="the tag of this template") + private String templateTag; + + @Override public Long getObjectId() { - return getId(); + return getId(); } - + public Long getZoneId() { return zoneId; } @@ -300,18 +304,25 @@ public class TemplateResponse extends BaseResponse { this.hypervisor = hypervisor; } + + public Long getJobId() { return jobId; } + + public void setJobId(Long jobId) { this.jobId = jobId; } + + public Integer getJobStatus() { return jobStatus; } + public void setJobStatus(Integer jobStatus) { this.jobStatus = jobStatus; } @@ -332,14 +343,14 @@ public class TemplateResponse extends BaseResponse { this.domainId = domainId; } - public Boolean isExtractable() { - return extractable; - } + public Boolean isExtractable() { + return extractable; + } + + public void setExtractable(Boolean extractable) { + this.extractable = extractable; + } - public void setExtractable(Boolean extractable) { - this.extractable = extractable; - } - public String getChecksum() { return checksum; } @@ -347,7 +358,7 @@ public class TemplateResponse extends BaseResponse { public void setChecksum(String checksum) { this.checksum = checksum; } - + public Long getSourceTemplateId() { return sourcetemplateId; } @@ -355,7 +366,7 @@ public class TemplateResponse extends BaseResponse { public void setSourceTemplateId(Long sourcetemplateId) { this.sourcetemplateId = sourcetemplateId; } - + public Long getHostId() { return hostId; } @@ -371,4 +382,12 @@ public class TemplateResponse extends BaseResponse { public void setHostName(String hostName) { this.hostName = hostName; } + + public String getTemplateTag() { + return templateTag; + } + + public void setTemplateTag(String templateTag) { + this.templateTag = templateTag; + } } diff --git a/api/src/com/cloud/template/VirtualMachineTemplate.java b/api/src/com/cloud/template/VirtualMachineTemplate.java index 4a512a302aa..a57cf2a3249 100755 --- a/api/src/com/cloud/template/VirtualMachineTemplate.java +++ b/api/src/com/cloud/template/VirtualMachineTemplate.java @@ -25,7 +25,7 @@ import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; public interface VirtualMachineTemplate extends ControlledEntity { - + public static enum BootloaderType { PyGrub, HVM, External, CD }; public enum TemplateFilter { featured, // returns templates that have been marked as featured and public @@ -36,53 +36,55 @@ public interface VirtualMachineTemplate extends ControlledEntity { community, // returns templates that have been marked as public but not featured all // all templates (only usable by ROOT admins) } - + /** * @return id. */ long getId(); - + boolean isFeatured(); - + /** * @return public or private template */ boolean isPublicTemplate(); - + boolean isExtractable(); - + /** * @return name */ String getName(); - + ImageFormat getFormat(); boolean isRequiresHvm(); - + String getDisplayText(); - + boolean getEnablePassword(); - + boolean isCrossZones(); - + Date getCreated(); - + long getGuestOSId(); - + boolean isBootable(); - + TemplateType getTemplateType(); - + HypervisorType getHypervisorType(); - + int getBits(); - + String getUniqueName(); - + String getUrl(); String getChecksum(); - Long getSourceTemplateId(); + Long getSourceTemplateId(); + + String getTemplateTag(); } diff --git a/core/src/com/cloud/storage/VMTemplateVO.java b/core/src/com/cloud/storage/VMTemplateVO.java index c7de111a494..df548dc34c7 100755 --- a/core/src/com/cloud/storage/VMTemplateVO.java +++ b/core/src/com/cloud/storage/VMTemplateVO.java @@ -41,369 +41,374 @@ import com.cloud.utils.db.GenericDao; @Entity @Table(name="vm_template") public class VMTemplateVO implements VirtualMachineTemplate { - @Id + @Id @TableGenerator(name="vm_template_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="vm_template_seq", allocationSize=1) @Column(name="id", nullable = false) - private long id; + private long id; + + @Column(name="format") + private Storage.ImageFormat format; - @Column(name="format") - private Storage.ImageFormat format; - @Column(name="unique_name") private String uniqueName; - + @Column(name="name") - private String name = null; - + private String name = null; + @Column(name="public") - private boolean publicTemplate = true; - + private boolean publicTemplate = true; + @Column(name="featured") private boolean featured; - + @Column(name="type") private Storage.TemplateType templateType; - + @Column(name="url") private String url = null; - + @Column(name="hvm") private boolean requiresHvm; - + @Column(name="bits") private int bits; @Temporal(value=TemporalType.TIMESTAMP) @Column(name=GenericDao.CREATED_COLUMN) private Date created = null; - + @Column(name=GenericDao.REMOVED) @Temporal(TemporalType.TIMESTAMP) private Date removed; - + @Column(name="account_id") private long accountId; - + @Column(name="checksum") private String checksum; - + @Column(name="display_text", length=4096) private String displayText; - + @Column(name="enable_password") private boolean enablePassword; - + @Column(name="guest_os_id") private long guestOSId; - + @Column(name="bootable") private boolean bootable = true; - + @Column(name="prepopulate") private boolean prepopulate = false; - + @Column(name="cross_zones") private boolean crossZones = false; - + @Column(name="hypervisor_type") @Enumerated(value=EnumType.STRING) private HypervisorType hypervisorType; - + @Column(name="extractable") private boolean extractable = true; - + @Column(name="source_template_id") - private Long sourceTemplateId; - + private Long sourceTemplateId; + + @Column(name="template_tag") + private String templateTag; + @Override public String getUniqueName() { - return uniqueName; - } - - public void setUniqueName(String uniqueName) { - this.uniqueName = uniqueName; - } - - protected VMTemplateVO() { + return uniqueName; } - /** - * Proper constructor for a new vm template. - */ + public void setUniqueName(String uniqueName) { + this.uniqueName = uniqueName; + } + + protected VMTemplateVO() { + } + + /** + * Proper constructor for a new vm template. + */ 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) { - this.id = id; - this.name = name; - this.publicTemplate = isPublic; - this.featured = featured; - 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; - } - - // 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; + this(id, generateUniqueName(id, accountId, name), name, format, isPublic, featured, isExtractable, type, url, null, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType); } - @Override - public boolean getEnablePassword() { - return enablePassword; - } - - @Override - public Storage.ImageFormat getFormat() { - return format; - } + 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, String templateTag) { + this(id, name, format, isPublic, featured, isExtractable, type, url, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType); + this.templateTag = templateTag; + } - public void setEnablePassword(boolean enablePassword) { - this.enablePassword = enablePassword; - } - - public void setFormat(ImageFormat format) { - this.format = format; - } - - private static String generateUniqueName(long id, long userId, String displayName) { - StringBuilder name = new StringBuilder(); - name.append(id); - name.append("-"); - name.append(userId); - name.append("-"); - name.append(UUID.nameUUIDFromBytes((displayName + System.currentTimeMillis()).getBytes()).toString()); - return name.toString(); - } - - @Override - public long getId() { - return id; - } - - @Override - public TemplateType getTemplateType() { - return templateType; - } - - public void setTemplateType(TemplateType type) { - this.templateType = type; - } - - public boolean requiresHvm() { - return requiresHvm; - } - - @Override - public int getBits() { - return bits; - } - - public void setBits(int bits) { - this.bits = bits; - } - + 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) { + this.id = id; + this.name = name; + this.publicTemplate = isPublic; + this.featured = featured; + 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; + } + + // 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, uniqueName, name, format, isPublic, featured, type, url, created, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType); + this.extractable = 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, String templateTag) { + this(id, uniqueName, name, format, isPublic, featured, isExtractable, type, url, created, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType); + this.templateTag = templateTag; + } + @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; + public boolean getEnablePassword() { + return enablePassword; } - + + @Override + public Storage.ImageFormat getFormat() { + return format; + } + + public void setEnablePassword(boolean enablePassword) { + this.enablePassword = enablePassword; + } + + public void setFormat(ImageFormat format) { + this.format = format; + } + + private static String generateUniqueName(long id, long userId, String displayName) { + StringBuilder name = new StringBuilder(); + name.append(id); + name.append("-"); + name.append(userId); + name.append("-"); + name.append(UUID.nameUUIDFromBytes((displayName + System.currentTimeMillis()).getBytes()).toString()); + return name.toString(); + } + + @Override + public long getId() { + return id; + } + + @Override + public TemplateType getTemplateType() { + return templateType; + } + + public void setTemplateType(TemplateType type) { + this.templateType = type; + } + + public boolean requiresHvm() { + return requiresHvm; + } + + @Override + public int getBits() { + return bits; + } + + public void setBits(int bits) { + this.bits = bits; + } + + @Override + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + public Date getRemoved() { return removed; } - + @Override - public boolean isPublicTemplate() { - return publicTemplate; - } - + public boolean isPublicTemplate() { + return publicTemplate; + } + public void setPublicTemplate(boolean publicTemplate) { - this.publicTemplate = publicTemplate; + this.publicTemplate = publicTemplate; } - + @Override public boolean isFeatured() { - return featured; + return featured; } - + public void setFeatured(boolean featured) { - this.featured = featured; + this.featured = featured; } - - @Override + + @Override public Date getCreated() { - return created; - } - - @Override + return created; + } + + @Override public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } + return url; + } + + public void setUrl(String url) { + this.url = url; + } - @Override + @Override public boolean isRequiresHvm() { - return requiresHvm; - } - - public void setRequiresHvm(boolean value) { - requiresHvm = value; - } + return requiresHvm; + } - @Override + public void setRequiresHvm(boolean value) { + requiresHvm = value; + } + + @Override public long getAccountId() { - return accountId; - } + return accountId; + } - @Override + @Override public String getChecksum() { - return checksum; - } - + return checksum; + } + public void setChecksum(String checksum) { this.checksum = checksum; } @Override public String getDisplayText() { - return displayText; - } + return displayText; + } - public void setDisplayText(String displayText) { - this.displayText = displayText; - } + public void setDisplayText(String displayText) { + this.displayText = displayText; + } - @Override + @Override public long getGuestOSId() { - return guestOSId; - } - - public void setGuestOSId(long guestOSId) { - this.guestOSId = guestOSId; - } - - @Override + return guestOSId; + } + + public void setGuestOSId(long guestOSId) { + this.guestOSId = guestOSId; + } + + @Override public boolean isBootable() { - return bootable; - } - - public void setBootable(boolean bootable) { - this.bootable = bootable; - } + return bootable; + } + + public void setBootable(boolean bootable) { + this.bootable = bootable; + } - public void setPrepopulate(boolean prepopulate) { - this.prepopulate = prepopulate; - } + public void setPrepopulate(boolean prepopulate) { + this.prepopulate = prepopulate; + } - public boolean isPrepopulate() { - return prepopulate; - } + public boolean isPrepopulate() { + return prepopulate; + } - public void setCrossZones(boolean crossZones) { - this.crossZones = crossZones; - } + public void setCrossZones(boolean crossZones) { + this.crossZones = crossZones; + } - @Override + @Override public boolean isCrossZones() { - return crossZones; - } - - @Override + return crossZones; + } + + @Override public HypervisorType getHypervisorType() { - return hypervisorType; - } - - public void setHypervisorType(HypervisorType hyperType) { - hypervisorType = hyperType; - } - - @Override - public boolean isExtractable() { - return extractable; - } + return hypervisorType; + } - public void setExtractable(boolean extractable) { - this.extractable = extractable; - } - - @Override - public Long getSourceTemplateId() { - return sourceTemplateId; - } - - public void setSourceTemplateId(Long sourceTemplateId) { - this.sourceTemplateId = sourceTemplateId; - } + public void setHypervisorType(HypervisorType hyperType) { + hypervisorType = hyperType; + } - @Override + @Override + public boolean isExtractable() { + return extractable; + } + + public void setExtractable(boolean extractable) { + this.extractable = extractable; + } + + @Override + public Long getSourceTemplateId() { + return sourceTemplateId; + } + + public void setSourceTemplateId(Long sourceTemplateId) { + this.sourceTemplateId = sourceTemplateId; + } + + @Override + public String getTemplateTag() { + return templateTag; + } + + public void setTemplateTag(String templateTag) { + this.templateTag = templateTag; + } + + @Override public long getDomainId() { - return -1; - } + return -1; + } - @Override - public boolean equals(Object that) { - if (this == that ) { + @Override + public boolean equals(Object that) { + if (this == that ) { return true; } - if (!(that instanceof VMTemplateVO)){ - return false; - } - VMTemplateVO other = (VMTemplateVO)that; - - return ((this.getUniqueName().equals(other.getUniqueName()))); - } + if (!(that instanceof VMTemplateVO)){ + return false; + } + VMTemplateVO other = (VMTemplateVO)that; - @Override - public int hashCode() { - return uniqueName.hashCode(); - } - - @Transient - String toString; - @Override + return ((this.getUniqueName().equals(other.getUniqueName()))); + } + + @Override + public int hashCode() { + return uniqueName.hashCode(); + } + + @Transient + String toString; + @Override public String toString() { - if (toString == null) { - toString = new StringBuilder("Tmpl[").append(id).append("-").append(format).append("-").append(uniqueName).toString(); - } - return toString; - } + if (toString == null) { + toString = new StringBuilder("Tmpl[").append(id).append("-").append(format).append("-").append(uniqueName).toString(); + } + return toString; + } public void setRemoved(Date removed) { this.removed = removed; diff --git a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java index 880b4fc6823..d5337fb3c76 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java @@ -92,18 +92,57 @@ public class FirstFitAllocator implements HostAllocator { return new ArrayList(); } - String hostTag = offering.getHostTag(); - if(hostTag != null){ - s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag); - }else{ - s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId); + if(s_logger.isDebugEnabled()){ + s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId ); } + + String hostTagOnOffering = offering.getHostTag(); + String hostTagOnTemplate = template.getTemplateTag(); + + boolean hasSvcOfferingTag = hostTagOnOffering != null ? true : false; + boolean hasTemplateTag = hostTagOnTemplate != null ? true : false; List clusterHosts = new ArrayList(); - if(hostTag != null){ - clusterHosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag); + if(hostTagOnOffering == null && hostTagOnTemplate == null){ + clusterHosts = _hostDao.listBy(type, clusterId, podId, dcId); }else{ - clusterHosts = _hostDao.listBy(type, clusterId, podId, dcId); + List hostsMatchingOfferingTag = new ArrayList(); + List hostsMatchingTemplateTag = new ArrayList(); + if(hasSvcOfferingTag){ + if(s_logger.isDebugEnabled()){ + s_logger.debug("Looking for hosts having tag specified on SvcOffering:" + hostTagOnOffering); + } + hostsMatchingOfferingTag = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnOffering); + if(s_logger.isDebugEnabled()){ + s_logger.debug("Hosts with tag '"+hostTagOnOffering+"' are:" + hostsMatchingOfferingTag); + } + } + if(hasTemplateTag){ + if(s_logger.isDebugEnabled()){ + s_logger.debug("Looking for hosts having tag specified on Template:" + hostTagOnTemplate); + } + hostsMatchingTemplateTag = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate); + if(s_logger.isDebugEnabled()){ + s_logger.debug("Hosts with tag '"+hostTagOnTemplate+"' are:" + hostsMatchingTemplateTag); + } + } + + if(hasSvcOfferingTag && hasTemplateTag){ + hostsMatchingOfferingTag.retainAll(hostsMatchingTemplateTag); + clusterHosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate); + if(s_logger.isDebugEnabled()){ + s_logger.debug("Found "+ hostsMatchingOfferingTag.size() +" Hosts satisfying both tags, host ids are:" + hostsMatchingOfferingTag); + } + + clusterHosts = hostsMatchingOfferingTag; + }else{ + if(hasSvcOfferingTag){ + clusterHosts = hostsMatchingOfferingTag; + }else{ + clusterHosts = hostsMatchingTemplateTag; + } + } + } return allocateTo(offering, template, avoid, clusterHosts, returnUpTo); diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 9c246c188dc..89700ced52f 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -19,9 +19,7 @@ package com.cloud.api; import java.text.DecimalFormat; import java.util.ArrayList; -import java.util.Collection; import java.util.Date; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -161,10 +159,10 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachine.Type; +import com.cloud.vm.VmStats; import com.cloud.vm.dao.UserVmData; import com.cloud.vm.dao.UserVmData.NicData; import com.cloud.vm.dao.UserVmData.SecurityGroupData; -import com.cloud.vm.VmStats; public class ApiResponseHelper implements ResponseGenerator { @@ -407,18 +405,18 @@ public class ApiResponseHelper implements ResponseGenerator { @Override public ResourceCountResponse createResourceCountResponse(ResourceCount resourceCount) { - ResourceCountResponse resourceCountResponse = new ResourceCountResponse(); + ResourceCountResponse resourceCountResponse = new ResourceCountResponse(); if (resourceCount.getAccountId() != null) { Account accountTemp = ApiDBUtils.findAccountById(resourceCount.getAccountId()); if (accountTemp != null) { - resourceCountResponse.setAccountName(accountTemp.getAccountName()); - resourceCountResponse.setDomainId(accountTemp.getDomainId()); - resourceCountResponse.setDomainName(ApiDBUtils.findDomainById(accountTemp.getDomainId()).getName()); + resourceCountResponse.setAccountName(accountTemp.getAccountName()); + resourceCountResponse.setDomainId(accountTemp.getDomainId()); + resourceCountResponse.setDomainName(ApiDBUtils.findDomainById(accountTemp.getDomainId()).getName()); } } else if (resourceCount.getDomainId() != null) { - resourceCountResponse.setDomainId(resourceCount.getDomainId()); - resourceCountResponse.setDomainName(ApiDBUtils.findDomainById(resourceCount.getDomainId()).getName()); + resourceCountResponse.setDomainId(resourceCount.getDomainId()); + resourceCountResponse.setDomainName(ApiDBUtils.findDomainById(resourceCount.getDomainId()).getName()); } resourceCountResponse.setResourceType(Integer.valueOf(resourceCount.getType().ordinal()).toString()); @@ -1097,8 +1095,8 @@ public class ApiResponseHelper implements ResponseGenerator { @Override public DomainRouterResponse createDomainRouterResponse(VirtualRouter router) { - Map serviceOfferings = new HashMap(); - + Map serviceOfferings = new HashMap(); + DomainRouterResponse routerResponse = new DomainRouterResponse(); routerResponse.setId(router.getId()); routerResponse.setZoneId(router.getDataCenterIdToDeployIn()); @@ -1114,7 +1112,7 @@ public class ApiResponseHelper implements ResponseGenerator { routerResponse.setHostId(router.getHostId()); routerResponse.setHostName(ApiDBUtils.findHostById(router.getHostId()).getName()); } - + // Service Offering Info ServiceOffering offering = serviceOfferings.get(router.getServiceOfferingId()); @@ -1124,7 +1122,7 @@ public class ApiResponseHelper implements ResponseGenerator { } routerResponse.setServiceOfferingId(offering.getId()); routerResponse.setServiceOfferingName(offering.getName()); - + Account accountTemp = ApiDBUtils.findAccountById(router.getAccountId()); if (accountTemp != null) { routerResponse.setAccountName(accountTemp.getAccountName()); @@ -1236,11 +1234,11 @@ public class ApiResponseHelper implements ResponseGenerator { return vmResponse; } - @Override - public Host findHostById(Long hostId) { - return ApiDBUtils.findHostById(hostId); - } - + @Override + public Host findHostById(Long hostId) { + return ApiDBUtils.findHostById(hostId); + } + @Override public User findUserById(Long userId) { return ApiDBUtils.findUserById(userId); @@ -1347,7 +1345,7 @@ public class ApiResponseHelper implements ResponseGenerator { return createTemplateResponses(templateId, zoneId.longValue(), readyOnly); } } - + @Override public List createTemplateResponses(long templateId, long zoneId, boolean readyOnly) { VirtualMachineTemplate template = findTemplateById(templateId); @@ -1396,15 +1394,15 @@ public class ApiResponseHelper implements ResponseGenerator { templateResponse.setDomainId(owner.getDomainId()); templateResponse.setDomainName(ApiDBUtils.findDomainById(owner.getDomainId()).getName()); } - - + + DataCenterVO datacenter = ApiDBUtils.findZoneById(zoneId); // Add the zone ID templateResponse.setZoneId(zoneId); templateResponse.setZoneName(datacenter.getName()); - + Account account = UserContext.current().getCaller(); boolean isAdmin = false; if ((account == null) || BaseCmd.isAdmin(account.getType())) { @@ -1443,6 +1441,8 @@ public class ApiResponseHelper implements ResponseGenerator { templateResponse.setChecksum(template.getChecksum()); + templateResponse.setTemplateTag(template.getTemplateTag()); + templateResponse.setObjectName("template"); responses.add(templateResponse); return responses; @@ -1487,7 +1487,7 @@ public class ApiResponseHelper implements ResponseGenerator { } } } - + @Override public List createIsoResponses(VirtualMachineTemplate iso, long zoneId, boolean readyOnly) { long isoId = iso.getId(); @@ -1697,13 +1697,13 @@ public class ApiResponseHelper implements ResponseGenerator { } return createTemplateResponses(templateId, volume.getDataCenterId(), readyOnly); } - + @Override public List createTemplateResponses(long templateId, Long vmId) { - UserVm vm = findUserVmById(vmId); - Long hostId = (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()); - Host host = findHostById(hostId); - return createTemplateResponses(templateId, host.getDataCenterId(), true); + UserVm vm = findUserVmById(vmId); + Long hostId = (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()); + Host host = findHostById(hostId); + return createTemplateResponses(templateId, host.getDataCenterId(), true); } @Override @@ -1756,13 +1756,13 @@ public class ApiResponseHelper implements ResponseGenerator { } short capacityType = capacity.getCapacityType(); - + //If local storage then ignore if ( (capacityType == Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED || capacityType == Capacity.CAPACITY_TYPE_STORAGE) - && poolIdsToIgnore.contains(capacity.getHostOrPoolId())) { + && poolIdsToIgnore.contains(capacity.getHostOrPoolId())) { continue; } - + String key = capacity.getCapacityType() + "_" + capacity.getDataCenterId(); String keyForPodTotal = key + "_-1"; @@ -2144,7 +2144,7 @@ public class ApiResponseHelper implements ResponseGenerator { response.setObjectName("network"); return response; } - + @Override public Long getSecurityGroupId (String groupName, long accountId) { SecurityGroup sg = ApiDBUtils.getSecurityGroup(groupName, accountId); @@ -2154,7 +2154,7 @@ public class ApiResponseHelper implements ResponseGenerator { return sg.getId(); } } - + @Override public FirewallResponse createFirewallResponse(FirewallRule fwRule) { FirewallResponse response = new FirewallResponse(); @@ -2164,11 +2164,11 @@ public class ApiResponseHelper implements ResponseGenerator { if (fwRule.getSourcePortStart() != null) { response.setStartPort(Integer.toString(fwRule.getSourcePortStart())); } - + if (fwRule.getSourcePortEnd() != null) { response.setEndPort(Integer.toString(fwRule.getSourcePortEnd())); } - + List cidrs = ApiDBUtils.findFirewallSourceCidrs(fwRule.getId()); response.setCidrList(StringUtils.join(cidrs, ",")); @@ -2181,10 +2181,10 @@ public class ApiResponseHelper implements ResponseGenerator { if (state.equals(FirewallRule.State.Revoke)) { stateToSet = "Deleting"; } - + response.setIcmpCode(fwRule.getIcmpCode()); response.setIcmpType(fwRule.getIcmpType()); - + response.setState(stateToSet); response.setObjectName("firewallrule"); return response; @@ -2276,7 +2276,7 @@ public class ApiResponseHelper implements ResponseGenerator { securityGroupResponse.add(sgr); } userVmResponse.setSecurityGroupList(new ArrayList(securityGroupResponse)); - + Set nicResponses = new HashSet(); for (NicData nd: userVmData.getNics()){ NicResponse nr = new NicResponse(); @@ -2295,8 +2295,8 @@ public class ApiResponseHelper implements ResponseGenerator { nicResponses.add(nr); } userVmResponse.setNics(new ArrayList(nicResponses)); - + return userVmResponse; } - + } diff --git a/server/src/com/cloud/template/TemplateAdapter.java b/server/src/com/cloud/template/TemplateAdapter.java index dfd750c9732..dada14ff4b9 100644 --- a/server/src/com/cloud/template/TemplateAdapter.java +++ b/server/src/com/cloud/template/TemplateAdapter.java @@ -41,4 +41,9 @@ public interface TemplateAdapter extends Adapter { Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, String accountName, Long domainId, String chksum, Boolean bootable) throws ResourceAllocationException; + + public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, + Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, + Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, + String accountName, Long domainId, String chksum, Boolean bootable, String templateTag) throws ResourceAllocationException; } diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index 007f46cd094..c916263bb87 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -23,9 +23,9 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VMTemplateZoneDao; @@ -38,7 +38,6 @@ import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.utils.EnumUtils; import com.cloud.utils.component.Inject; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.UserVmVO; public abstract class TemplateAdapterBase implements TemplateAdapter { @@ -84,10 +83,17 @@ public abstract class TemplateAdapterBase implements TemplateAdapter { (accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)); } + public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, + Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, + Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, + String accountName, Long domainId, String chksum, Boolean bootable) throws ResourceAllocationException { + return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId, hypervisorType, + accountName, domainId, chksum, bootable, null); + } public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, - String accountName, Long domainId, String chksum, Boolean bootable) throws ResourceAllocationException { + String accountName, Long domainId, String chksum, Boolean bootable, String templateTag) throws ResourceAllocationException { Account ctxAccount = UserContext.current().getCaller(); Account resourceAccount = null; Long accountId = null; @@ -229,7 +235,7 @@ public abstract class TemplateAdapterBase implements TemplateAdapter { Long id = _tmpltDao.getNextInSequence(Long.class, "id"); UserContext.current().setEventDetails("Id: " +id+ " name: " + name); return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, - featured, isExtractable, imgfmt, guestOSId, zoneId, hypervisorType, accountName, domainId, accountId, chksum, true); + featured, isExtractable, imgfmt, guestOSId, zoneId, hypervisorType, accountName, domainId, accountId, chksum, true, templateTag); } @Override @@ -237,13 +243,13 @@ public abstract class TemplateAdapterBase implements TemplateAdapter { return prepare(false, UserContext.current().getCallerUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(), cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), cmd.getZoneId(), HypervisorType.getType(cmd.getHypervisor()), - cmd.getAccountName(), cmd.getDomainId(), cmd.getChecksum(), true); + cmd.getAccountName(), cmd.getDomainId(), cmd.getChecksum(), true, cmd.getTemplateTag()); } public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { return prepare(true, UserContext.current().getCallerUserId(), cmd.getIsoName(), cmd.getDisplayText(), 64, false, true, cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), ImageFormat.ISO.toString(), cmd.getOsTypeId(), - cmd.getZoneId(), HypervisorType.None, cmd.getAccountName(), cmd.getDomainId(), null, cmd.isBootable()); + cmd.getZoneId(), HypervisorType.None, cmd.getAccountName(), cmd.getDomainId(), null, cmd.isBootable(), null); } protected VMTemplateVO persistTemplate(TemplateProfile profile) { @@ -251,7 +257,7 @@ public abstract class TemplateAdapterBase implements TemplateAdapter { VMTemplateVO template = new VMTemplateVO(profile.getTemplateId(), profile.getName(), profile.getFormat(), profile.getIsPublic(), profile.getFeatured(), profile.getIsExtractable(), TemplateType.USER, profile.getUrl(), profile.getRequiresHVM(), profile.getBits(), profile.getAccountId(), profile.getCheckSum(), profile.getDisplayText(), - profile.getPasswordEnabled(), profile.getGuestOsId(), profile.getBootable(), profile.getHypervisorType()); + profile.getPasswordEnabled(), profile.getGuestOsId(), profile.getBootable(), profile.getHypervisorType(), profile.getTemplateTag()); if (zoneId == null || zoneId == -1) { List dcs = _dcDao.listAllIncludingRemoved(); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 38f77cc2c04..c15fa5a7b78 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -103,6 +103,7 @@ import com.cloud.storage.upload.UploadMonitor; import com.cloud.template.TemplateAdapter.TemplateAdapterType; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.AccountService; import com.cloud.user.AccountVO; import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; @@ -162,6 +163,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe @Inject ConfigurationDao _configDao; @Inject UsageEventDao _usageEventDao; @Inject HypervisorGuruManager _hvGuruMgr; + @Inject AccountService _accountService; protected SearchBuilder HostTemplateStatesSearch; int _storagePoolMaxWaitSeconds = 3600; @@ -197,6 +199,12 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template") public VirtualMachineTemplate registerTemplate(RegisterTemplateCmd cmd) throws URISyntaxException, ResourceAllocationException{ + if(cmd.getTemplateTag() != null){ + Account account = UserContext.current().getCaller(); + if(!_accountService.isRootAdmin(account.getType())){ + throw new PermissionDeniedException("Parameter templatetag can only be specified by a Root Admin, permission denied"); + } + } TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor())); TemplateProfile profile = adapter.prepare(cmd); return adapter.create(profile); diff --git a/server/src/com/cloud/template/TemplateProfile.java b/server/src/com/cloud/template/TemplateProfile.java index 12424f97d30..f5e7ee39285 100644 --- a/server/src/com/cloud/template/TemplateProfile.java +++ b/server/src/com/cloud/template/TemplateProfile.java @@ -26,6 +26,7 @@ public class TemplateProfile { Boolean bootable; Long templateId; VMTemplateVO template; + String templateTag; public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, Long zoneId, @@ -58,6 +59,14 @@ public class TemplateProfile { this.zoneId = zoneId; } + public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, + String url, Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, Long zoneId, + HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag) { + this(templateId, userId, name, displayText, bits, passwordEnabled, requiresHvm, url, isPublic, featured, isExtractable, format, guestOsId, zoneId, + hypervisorType, accountName, domainId, accountId, chksum, bootable); + this.templateTag = templateTag; + } + public Long getTemplateId() { return templateId; } @@ -198,4 +207,12 @@ public class TemplateProfile { this.template = template; } + public String getTemplateTag() { + return templateTag; + } + + public void setTemplateTag(String templateTag) { + this.templateTag = templateTag; + } + } diff --git a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java index 7a4881a8139..c4111be6035 100755 --- a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -41,6 +41,7 @@ import com.cloud.upgrade.dao.DbUpgrade; import com.cloud.upgrade.dao.Upgrade217to218; import com.cloud.upgrade.dao.Upgrade218to22; import com.cloud.upgrade.dao.Upgrade218to224DomainVlans; +import com.cloud.upgrade.dao.Upgrade2210to2211; import com.cloud.upgrade.dao.Upgrade221to222; import com.cloud.upgrade.dao.Upgrade222to224; import com.cloud.upgrade.dao.Upgrade224to225; @@ -72,18 +73,19 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker { public DatabaseUpgradeChecker() { _dao = ComponentLocator.inject(VersionDaoImpl.class); - _upgradeMap.put("2.1.7", new DbUpgrade[] { new Upgrade217to218(), new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.1.8", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.1.9", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.2.1", new DbUpgrade[] { new Upgrade221to222(), new UpgradeSnapshot223to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.2.2", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.2.3", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.2.4", new DbUpgrade[] { new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.2.5", new DbUpgrade[] { new Upgrade225to226(), new Upgrade227to228(),new Upgrade228to229(), new Upgrade229to2210() }); - _upgradeMap.put("2.2.6", new DbUpgrade[] { new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.2.7", new DbUpgrade[] { new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.2.8", new DbUpgrade[] { new Upgrade228to229(), new Upgrade229to2210()}); - _upgradeMap.put("2.2.9", new DbUpgrade[] { new Upgrade229to2210()}); + _upgradeMap.put("2.1.7", new DbUpgrade[] { new Upgrade217to218(), new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.1.8", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.1.9", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.1", new DbUpgrade[] { new Upgrade221to222(), new UpgradeSnapshot223to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.2", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.3", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.4", new DbUpgrade[] { new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.5", new DbUpgrade[] { new Upgrade225to226(), new Upgrade227to228(),new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211() }); + _upgradeMap.put("2.2.6", new DbUpgrade[] { new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.7", new DbUpgrade[] { new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.8", new DbUpgrade[] { new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.9", new DbUpgrade[] { new Upgrade229to2210(), new Upgrade2210to2211()}); + _upgradeMap.put("2.2.10", new DbUpgrade[] { new Upgrade2210to2211()}); } protected void runScript(Connection conn, File file) { diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2210to2211.java b/server/src/com/cloud/upgrade/dao/Upgrade2210to2211.java new file mode 100644 index 00000000000..3ba74974b55 --- /dev/null +++ b/server/src/com/cloud/upgrade/dao/Upgrade2210to2211.java @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.upgrade.dao; + +import java.io.File; +import java.sql.Connection; + +import org.apache.log4j.Logger; + +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; + +public class Upgrade2210to2211 implements DbUpgrade { + final static Logger s_logger = Logger.getLogger(Upgrade2210to2211.class); + + @Override + public String[] getUpgradableVersionRange() { + return new String[] { "2.2.10", "2.2.10"}; + } + + @Override + public String getUpgradedVersion() { + return "2.2.11"; + } + + @Override + public boolean supportsRollingUpgrade() { + return true; + } + + @Override + public File[] getPrepareScripts() { + String script = Script.findScript("", "db/schema-2210to2211.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-2210to2211.sql"); + } + + return new File[] { new File(script) }; + } + + @Override + public void performDataMigration(Connection conn) { + } + + @Override + public File[] getCleanupScripts() { + return null; + } + +} diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 7a4005f7c7d..43c7c90591a 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -489,7 +489,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if (!(Volume.State.Allocated.equals(volume.getState())) && !_storageMgr.volumeOnSharedStoragePool(volume)) { throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool."); } - + if (!(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Ready.equals(volume.getState()))) { throw new InvalidParameterValueException("Volume state must be in Allocated or Ready state"); } @@ -865,7 +865,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager cmd.setStoreUrl(isoPathPair.second()); } Answer a = _agentMgr.easySend(vm.getHostId(), cmd); - + return (a != null && a.getResult()); } @@ -1151,7 +1151,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager _executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("UserVm-Scavenger")); _itMgr.registerGuru(VirtualMachine.Type.User, this); - + VirtualMachine.State.getStateMachine().registerListener(new UserVmStateListener(_usageEventDao, _networkDao, _nicDao)); s_logger.info("User VM Manager is configured."); @@ -1234,7 +1234,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager boolean success = true; //Remove vm from security groups _securityGroupMgr.removeInstanceFromGroups(vmId); - + //Remove vm from instance group removeInstanceFromInstanceGroup(vmId); @@ -1303,6 +1303,12 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if ((name == null) || (name.length() > 32)) { throw new InvalidParameterValueException("Template name cannot be null and should be less than 32 characters"); } + + if(cmd.getTemplateTag() != null){ + if(!_accountService.isRootAdmin(account.getType())){ + throw new PermissionDeniedException("Parameter templatetag can only be specified by a Root Admin, permission denied"); + } + } // do some parameter defaulting Integer bits = cmd.getBits(); @@ -1405,14 +1411,20 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); isExtractable = template != null && template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM; if (template != null){ - sourceTemplateId = template.getId(); + sourceTemplateId = template.getId(); }else if (volume.getVolumeType() == Type.ROOT){ //vm created out of blank template - UserVm userVm = ApiDBUtils.findUserVmById(volume.getInstanceId()); - sourceTemplateId = userVm.getIsoId(); + UserVm userVm = ApiDBUtils.findUserVmById(volume.getInstanceId()); + sourceTemplateId = userVm.getIsoId(); + } + } + String templateTag = cmd.getTemplateTag(); + if(templateTag != null){ + if(s_logger.isDebugEnabled()){ + s_logger.debug("Adding template tag: "+templateTag); } } privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name, ImageFormat.RAW, isPublic, featured, isExtractable, TemplateType.USER, null, null, requiresHvmValue, bitsValue, accountId, - null, description, passwordEnabledValue, guestOS.getId(), true, hyperType); + null, description, passwordEnabledValue, guestOS.getId(), true, hyperType, templateTag); if(sourceTemplateId != null){ if(s_logger.isDebugEnabled()){ s_logger.debug("This template is getting created from other template, setting source template Id to: "+sourceTemplateId); @@ -1527,7 +1539,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager throw new CloudRuntimeException("Unable to find volume for Id " + volumeId); } accountId = volume.getAccountId(); - + if (volume.getPoolId() == null) { _templateDao.remove(templateId); throw new CloudRuntimeException("Volume " + volumeId + " is empty, can't create template on it"); @@ -1586,9 +1598,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager // Specify RAW format makes it unusable for snapshots. privateTemplate.setFormat(ImageFormat.RAW); } - + String checkSum = getChecksum(secondaryStorageHost.getId(), answer.getPath()); - + Transaction txn = Transaction.currentTxn(); txn.start(); @@ -2056,9 +2068,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } else { networkList.add(_networkDao.findById(defaultNetwork.getId())); } - + boolean isVmWare = (template.getHypervisorType() == HypervisorType.VMware || (hypervisor != null && hypervisor == HypervisorType.VMware)); - + if (securityGroupIdList != null && isVmWare) { throw new InvalidParameterValueException("Security group feature is not supported for vmWare hypervisor"); } else if (!isVmWare) { @@ -2067,7 +2079,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } SecurityGroup defaultGroup = _securityGroupMgr.getDefaultSecurityGroup(owner.getId()); if (defaultGroup != null) { - //check if security group id list already contains Default security group, and if not - add it + //check if security group id list already contains Default security group, and if not - add it boolean defaultGroupPresent = false; for (Long securityGroupId : securityGroupIdList) { if (securityGroupId.longValue() == defaultGroup.getId()) { @@ -2075,11 +2087,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager break; } } - + if (!defaultGroupPresent) { securityGroupIdList.add(defaultGroup.getId()); } - + } else { //create default security group for the account if (s_logger.isDebugEnabled()) { @@ -2089,9 +2101,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager securityGroupIdList.add(defaultGroup.getId()); } } - + return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, - diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIp, keyboard); + diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIp, keyboard); } @Override @@ -2104,7 +2116,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager List networkList = new ArrayList(); boolean isSecurityGroupEnabledNetworkUsed = false; boolean isVmWare = (template.getHypervisorType() == HypervisorType.VMware || (hypervisor != null && hypervisor == HypervisorType.VMware)); - + //Verify that caller can perform actions in behalf of vm owner _accountMgr.checkAccess(caller, null, owner); @@ -2138,7 +2150,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager networkList.add(network); isSecurityGroupEnabledNetworkUsed = true; - + } else { // Verify that all the networks are Direct/Guest/AccountSpecific; can't create combination of SG enabled network and // regular networks @@ -2169,16 +2181,16 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager networkList.add(network); } } - + // if network is security group enabled, and default security group is not present in the list of groups specified, add it automatically if (isSecurityGroupEnabledNetworkUsed && !isVmWare) { if (securityGroupIdList == null) { securityGroupIdList = new ArrayList(); } - + SecurityGroup defaultGroup = _securityGroupMgr.getDefaultSecurityGroup(owner.getId()); if (defaultGroup != null) { - //check if security group id list already contains Default security group, and if not - add it + //check if security group id list already contains Default security group, and if not - add it boolean defaultGroupPresent = false; for (Long securityGroupId : securityGroupIdList) { if (securityGroupId.longValue() == defaultGroup.getId()) { @@ -2186,11 +2198,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager break; } } - + if (!defaultGroupPresent) { securityGroupIdList.add(defaultGroup.getId()); } - + } else { //create default security group for the account if (s_logger.isDebugEnabled()) { @@ -2200,7 +2212,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager securityGroupIdList.add(defaultGroup.getId()); } } - + return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIp, keyboard); } @@ -2306,7 +2318,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if (networkOffering.getAvailability() == Availability.Unavailable) { throw new InvalidParameterValueException("Network id=" + network.getId() + " can't be used; corresponding network offering is " + Availability.Unavailable); } - + //don't allow to use system networks if (networkOffering.isSystemOnly()) { throw new InvalidParameterValueException("Network id=" + networkId + " is system only and can't be used for vm deployment"); @@ -2335,7 +2347,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager _accountMgr.checkAccess(caller, null, owner); long accountId = owner.getId(); - + assert !(requestedIps != null && defaultNetworkIp != null) : "requestedIp list and defaultNetworkIp should never be specified together"; if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { @@ -2360,7 +2372,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager rae.setResourceType("vm"); throw rae; } - + //verify security group ids if (securityGroupIdList != null) { for (Long securityGroupId : securityGroupIdList) { @@ -2458,13 +2470,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager List> networks = new ArrayList>(); short defaultNetworkNumber = 0; for (NetworkVO network : networkList) { - + if (network.getDataCenterId() != zone.getId()) { throw new InvalidParameterValueException("Network id=" + network.getId() + " doesn't belong to zone " + zone.getId()); } NicProfile profile = null; - + //Add requested ips if (requestedIps != null && requestedIps.get(network.getId()) != null) { profile = new NicProfile(requestedIps.get(network.getId())); @@ -2478,7 +2490,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager profile = new NicProfile(defaultNetworkIp); } } - + networks.add(new Pair(network, profile)); } @@ -2518,14 +2530,14 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if (sshPublicKey != null) { vm.setDetail("SSH.PublicKey", sshPublicKey); } - + if(keyboard != null && !keyboard.isEmpty()) - vm.setDetail(VirtualMachine.PARAM_KEY_KEYBOARD, keyboard); + vm.setDetail(VirtualMachine.PARAM_KEY_KEYBOARD, keyboard); if (isIso) { vm.setIsoId(template.getId()); } - + s_logger.debug("Allocating in the DB for vm"); if (_itMgr.allocate(vm, _templateDao.findById(template.getId()), offering, rootDiskOffering, dataDiskOfferings, networks, null, plan, hypervisorType, owner) == null) { @@ -2541,7 +2553,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_CREATE, accountId, zone.getId(), vm.getId(), vm.getHostName(), offering.getId(), template.getId(), hypervisorType.toString()); _usageEventDao.persist(usageEvent); - + _accountMgr.incrementResourceCount(accountId, ResourceType.user_vm); txn.commit(); // Assign instance to the group @@ -2556,9 +2568,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager throw new CloudRuntimeException("Unable to assign Vm to the group " + group); } - + _securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList); - + return vm; } @@ -2662,7 +2674,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager UserVmVO vm = profile.getVirtualMachine(); Map details = _vmDetailsDao.findDetails(vm.getId()); vm.setDetails(details); - + Account owner = _accountDao.findById(vm.getAccountId()); if (owner == null) { @@ -2672,7 +2684,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if (owner.getState() == Account.State.disabled) { throw new PermissionDeniedException("The owner of " + vm + " is disabled: " + vm.getAccountId()); } - + if (vm.getIsoId() != null) { String isoPath = null; @@ -2689,7 +2701,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } else { isoPath = isoPathPair.first(); } - + if (template.isBootable()) { profile.setBootLoaderType(BootloaderType.CD); } @@ -2703,13 +2715,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager iso.setDeviceId(3); profile.addDisk(iso); } else { - VirtualMachineTemplate template = profile.getTemplate(); + VirtualMachineTemplate template = profile.getTemplate(); /* create a iso placeholder */ VolumeTO iso = new VolumeTO(profile.getId(), Volume.Type.ISO, StoragePoolType.ISO, null, template.getName(), null, null, 0, null); iso.setDeviceId(3); profile.addDisk(iso); } - + return true; } @@ -2869,14 +2881,14 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager userId = accountAndUserValidation(vmId, account, userId, vm); UserVO user = _userDao.findById(userId); - + //check if vm is security group enabled if (_securityGroupMgr.isVmSecurityGroupEnabled(vmId) && !_securityGroupMgr.isVmMappedToDefaultSecurityGroup(vmId)) { //if vm is not mapped to security group, create a mapping if (s_logger.isDebugEnabled()) { s_logger.debug("Vm " + vm + " is security group enabled, but not mapped to default security group; creating the mapping automatically"); } - + SecurityGroup defaultSecurityGroup = _securityGroupMgr.getDefaultSecurityGroup(vm.getAccountId()); if (defaultSecurityGroup != null) { List groupList = new ArrayList(); @@ -2884,7 +2896,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager _securityGroupMgr.addInstanceToGroups(vmId, groupList); } } - + return _itMgr.start(vm, null, user, account); } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index aa4a125b246..d81036cbb6e 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -841,6 +841,7 @@ CREATE TABLE `cloud`.`vm_template` ( `extractable` int(1) unsigned NOT NULL default 0 COMMENT 'Is this template extractable', `hypervisor_type` varchar(32) COMMENT 'hypervisor that the template belongs to', `source_template_id` bigint unsigned COMMENT 'Id of the original template, if this template is created from snapshot', + `template_tag` varchar(255) COMMENT 'template tag', PRIMARY KEY (`id`), INDEX `i_vm_template__removed`(`removed`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/db/db/schema-2210to2211.sql b/setup/db/db/schema-2210to2211.sql new file mode 100644 index 00000000000..cd7d30c6cd0 --- /dev/null +++ b/setup/db/db/schema-2210to2211.sql @@ -0,0 +1,6 @@ +--; +-- Schema upgrade from 2.2.10 to 2.2.11; +--; + +ALTER TABLE `cloud`.`vm_template` ADD COLUMN `template_tag` varchar(255) COMMENT 'template tag'; +