From 3eb48821c6a6e4f80c2c5cb4ac67feb3da9af017 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 7 May 2012 11:10:57 -0700 Subject: [PATCH 01/13] CS-14295: cloudstack 3.0 UI - volume page - upload volume dialog - add checksum field. --- ui/scripts/storage.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 52e6ebed595..1ddefd997fe 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -214,7 +214,10 @@ url: { label: 'label.url', validation: { required: true } - } + }, + checksum : { + label: 'label.checksum' + } } }, @@ -224,6 +227,8 @@ array1.push("&zoneId=" + args.data.availabilityZone); array1.push("&format=" + args.data.format); array1.push("&url=" + todb(args.data.url)); + if(args.data.checksum != null && args.data.checksum.length > 0) + array1.push("&checksum=" + todb(args.data.checksum)); $.ajax({ url: createURL("uploadVolume" + array1.join("")), From a45486a6f33d9c12b088659362fb900b5e1ee0d4 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 7 May 2012 11:27:49 -0700 Subject: [PATCH 02/13] cloudstack 3.0 UI - localization - add new label of MD5 checksum --- client/WEB-INF/classes/resources/messages.properties | 1 + ui/index.jsp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 9bb701dda54..47040c75a1c 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -11,6 +11,7 @@ label.number.of.virtual.routers=Number of Virtual Routers label.action.register.iso=Register ISO label.isolation.method=Isolation method label.action.register.template=Register template +label.checksum=MD5 checksum #new labels (end) ************************************************************************************************ diff --git a/ui/index.jsp b/ui/index.jsp index c4b198ffe39..c1367697f3e 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -2958,6 +2958,7 @@ dictionary = { 'message.validate.instance.name': '', 'label.action.register.template': '', 'label.action.register.iso': '', -'label.isolation.method': '' +'label.isolation.method': '', +'label.checksum': '' }; From 43f0d0df3520b5b3082a961139ca508290f8b6eb Mon Sep 17 00:00:00 2001 From: prachi Date: Fri, 4 May 2012 15:47:31 -0700 Subject: [PATCH 03/13] Logging related Changes overwritten by S3 Merger Also did changes to not log the hibernate SQL --- awsapi/conf/CloudStack.cfg.xml | 2 +- awsapi/conf/hibernate.cfg.xml | 2 +- awsapi/conf/log4j-cloud-bridge.xml | 68 ------------------- .../controller/s3/ServiceProvider.java | 4 +- 4 files changed, 5 insertions(+), 71 deletions(-) delete mode 100644 awsapi/conf/log4j-cloud-bridge.xml diff --git a/awsapi/conf/CloudStack.cfg.xml b/awsapi/conf/CloudStack.cfg.xml index d34d2f55367..1ba6f5ccf02 100644 --- a/awsapi/conf/CloudStack.cfg.xml +++ b/awsapi/conf/CloudStack.cfg.xml @@ -14,7 +14,7 @@ true org.hibernate.dialect.MySQLDialect - true + false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java b/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java index c00f2a202a8..18acb1a9ca3 100644 --- a/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java +++ b/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java @@ -198,7 +198,7 @@ public class ServiceProvider { if(logger.isInfoEnabled()) logger.info("Initializing ServiceProvider..."); - File file = ConfigurationHelper.findConfigurationFile("log4j-cloud-bridge.xml"); + File file = ConfigurationHelper.findConfigurationFile("log4j-cloud.xml"); if(file != null) { System.out.println("Log4j configuration from : " + file.getAbsolutePath()); DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000); @@ -327,6 +327,7 @@ public class ServiceProvider { try { result = method.invoke(serviceObject, args); PersistContext.commitTransaction(); + PersistContext.commitTransaction(true); } catch (PersistException e) { } catch (SessionException e) { } catch(Throwable e) { @@ -345,6 +346,7 @@ public class ServiceProvider { } } finally { PersistContext.closeSession(); + PersistContext.closeSession(true); } return result; } From 31bf4eb4269009cb23dc89e1974b85f008432441 Mon Sep 17 00:00:00 2001 From: prachi Date: Mon, 7 May 2012 11:36:51 -0700 Subject: [PATCH 04/13] EC2 API fidelity: Implement support for image attribute - launchPermission Now SOAP EC2 API supports launchPermission attribute for following commands: - ec2-describe-image-attribute - ec2-modify-image-attribute - ec2-reset-image-attribute Note: - REST API is not changed. - ec2 tools have some validation for userId to be AWS account id (8 digits). SO its is not possible to test adding or removing individual userIds in ec2-modify-image-attribute command. --- .../cloud/bridge/service/EC2MainServlet.java | 3 +- .../bridge/service/EC2SoapServiceImpl.java | 125 +++++++++++++---- .../core/ec2/EC2DescribeImageAttribute.java | 46 +++++++ .../bridge/service/core/ec2/EC2Engine.java | 126 +++++++++++++++--- .../service/core/ec2/EC2ImageAttributes.java | 86 ++++++++++++ .../core/ec2/EC2ModifyImageAttribute.java | 94 +++++++++++++ awsapi/src/com/cloud/stack/CloudStackApi.java | 6 +- .../models/CloudStackTemplatePermission.java | 12 +- 8 files changed, 449 insertions(+), 49 deletions(-) create mode 100644 awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeImageAttribute.java create mode 100644 awsapi/src/com/cloud/bridge/service/core/ec2/EC2ImageAttributes.java create mode 100644 awsapi/src/com/cloud/bridge/service/core/ec2/EC2ModifyImageAttribute.java diff --git a/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java b/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java index e647970cd7b..a0bcd41e486 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java +++ b/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java @@ -37,8 +37,9 @@ public class EC2MainServlet extends HttpServlet{ if(value != null){ isEC2APIEnabled = Boolean.valueOf(value); } - PersistContext.commitTransaction(true); + }finally { + PersistContext.commitTransaction(true); PersistContext.closeSession(true); } diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java index 34d3b80153f..0f0e309db88 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java +++ b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java @@ -36,6 +36,8 @@ import com.cloud.bridge.service.core.ec2.EC2DescribeAddresses; import com.cloud.bridge.service.core.ec2.EC2DescribeAddressesResponse; import com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZones; import com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZonesResponse; +import com.cloud.bridge.service.core.ec2.EC2DescribeImageAttribute; + import com.cloud.bridge.service.core.ec2.EC2DescribeImages; import com.cloud.bridge.service.core.ec2.EC2DescribeImagesResponse; import com.cloud.bridge.service.core.ec2.EC2DescribeInstances; @@ -53,11 +55,14 @@ import com.cloud.bridge.service.core.ec2.EC2Engine; import com.cloud.bridge.service.core.ec2.EC2Filter; import com.cloud.bridge.service.core.ec2.EC2GroupFilterSet; import com.cloud.bridge.service.core.ec2.EC2Image; +import com.cloud.bridge.service.core.ec2.EC2ImageAttributes; +import com.cloud.bridge.service.core.ec2.EC2ImageAttributes.ImageAttribute; import com.cloud.bridge.service.core.ec2.EC2ImportKeyPair; import com.cloud.bridge.service.core.ec2.EC2Instance; import com.cloud.bridge.service.core.ec2.EC2InstanceFilterSet; import com.cloud.bridge.service.core.ec2.EC2IpPermission; import com.cloud.bridge.service.core.ec2.EC2KeyPairFilterSet; +import com.cloud.bridge.service.core.ec2.EC2ModifyImageAttribute; import com.cloud.bridge.service.core.ec2.EC2PasswordData; import com.cloud.bridge.service.core.ec2.EC2RebootInstances; import com.cloud.bridge.service.core.ec2.EC2RegisterImage; @@ -226,18 +231,25 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { /** * This only supports a query about description. */ - public DescribeImageAttributeResponse describeImageAttribute(DescribeImageAttribute describeImageAttribute) { - EC2DescribeImages request = new EC2DescribeImages(); - DescribeImageAttributeType diat = describeImageAttribute.getDescribeImageAttribute(); - DescribeImageAttributesGroup diag = diat.getDescribeImageAttributesGroup(); - EmptyElementType description = diag.getDescription(); + public DescribeImageAttributeResponse describeImageAttribute(DescribeImageAttribute describeImageAttribute) { + EC2DescribeImageAttribute request = new EC2DescribeImageAttribute(); + DescribeImageAttributeType diat = describeImageAttribute.getDescribeImageAttribute(); + DescribeImageAttributesGroup diag = diat.getDescribeImageAttributesGroup(); + EmptyElementType description = diag.getDescription(); + EmptyElementType launchPermission = diag.getLaunchPermission(); + + if ( null != description ) { + request.setImageId(diat.getImageId()); + request.setAttribute(ImageAttribute.description); + return toDescribeImageAttributeResponse( engine.describeImageAttribute( request )); + }else if(launchPermission != null){ + request.setImageId(diat.getImageId()); + request.setAttribute(ImageAttribute.launchPermission); + return toDescribeImageAttributeResponse( engine.describeImageAttribute( request )); + } + else throw new EC2ServiceException( "Unsupported - only description or launchPermission supported", 501 ); + } - if ( null != description ) { - request.addImageSet(diat.getImageId()); - return toDescribeImageAttributeResponse( engine.describeImages( request )); - } - else throw new EC2ServiceException( "Unsupported - only description supported", 501 ); - } public DescribeImagesResponse describeImages(DescribeImages describeImages) { EC2DescribeImages request = new EC2DescribeImages(); @@ -446,26 +458,50 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { } public ModifyImageAttributeResponse modifyImageAttribute(ModifyImageAttribute modifyImageAttribute) { - // TODO: This is broken - EC2Image request = new EC2Image(); + EC2ModifyImageAttribute request = new EC2ModifyImageAttribute(); ModifyImageAttributeType miat = modifyImageAttribute.getModifyImageAttribute(); ModifyImageAttributeTypeChoice_type0 item = miat.getModifyImageAttributeTypeChoice_type0(); AttributeValueType description = item.getDescription(); - /* + LaunchPermissionOperationType launchPermOp = item.getLaunchPermission(); - ProductCodeListType prodCodeList =item.getProductCodes(); - */ if (null != description) { - request.setId( miat.getImageId()); + request.setImageId(miat.getImageId()); + request.setAttribute(ImageAttribute.description); request.setDescription(description.getValue()); return toModifyImageAttributeResponse( engine.modifyImageAttribute( request )); + }else if(launchPermOp != null){ + request.setImageId(miat.getImageId()); + request.setAttribute(ImageAttribute.launchPermission); + if(launchPermOp.getAdd() != null){ + request.setLaunchPermOperation(EC2ModifyImageAttribute.Operation.add); + setAccountOrGroupList(launchPermOp.getAdd().getItem(), request); + }else if(launchPermOp.getRemove() != null){ + request.setLaunchPermOperation(EC2ModifyImageAttribute.Operation.remove); + setAccountOrGroupList(launchPermOp.getRemove().getItem(), request); + } + return toModifyImageAttributeResponse( engine.modifyImageAttribute( request )); } - throw new EC2ServiceException( "Unsupported - can only modify image description", 501 ); + throw new EC2ServiceException( "Unsupported - can only modify image description or launchPermission", 501 ); } + private void setAccountOrGroupList(LaunchPermissionItemType[] items, EC2ModifyImageAttribute request){ + + List launchPermissionAccountsOrGroupList = new ArrayList(); + + for (LaunchPermissionItemType lpItem : items) { + if(lpItem.getGroup() != null){ + launchPermissionAccountsOrGroupList.add(lpItem.getGroup()); + }else if(lpItem.getUserId() != null){ + launchPermissionAccountsOrGroupList.add(lpItem.getUserId()); + } + } + + request.setLaunchPermissionAccountsOrGroupList(launchPermissionAccountsOrGroupList); + + } /** * Did not find a matching service offering so for now we just return disabled * for each instance request. We could verify that all of the specified instances @@ -541,12 +577,16 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { */ public ResetImageAttributeResponse resetImageAttribute(ResetImageAttribute resetImageAttribute) { - EC2Image request = new EC2Image(); + EC2ModifyImageAttribute request = new EC2ModifyImageAttribute(); ResetImageAttributeType riat = resetImageAttribute.getResetImageAttribute(); - - request.setId( riat.getImageId()); - request.setDescription( "" ); - return toResetImageAttributeResponse( engine.modifyImageAttribute( request )); + EmptyElementType elementType = riat.getResetImageAttributesGroup().getLaunchPermission(); + if(elementType != null){ + request.setImageId( riat.getImageId()); + request.setAttribute(ImageAttribute.launchPermission); + request.setLaunchPermOperation(EC2ModifyImageAttribute.Operation.reset); + return toResetImageAttributeResponse( engine.modifyImageAttribute( request )); + } + throw new EC2ServiceException( "Unsupported - can only reset image launchPermission", 501 ); } /** @@ -678,6 +718,45 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { return response; } + public static DescribeImageAttributeResponse toDescribeImageAttributeResponse(EC2ImageAttributes engineResponse) { + DescribeImageAttributeResponse response = new DescribeImageAttributeResponse(); + DescribeImageAttributeResponseType param1 = new DescribeImageAttributeResponseType(); + + if (engineResponse != null ) { + DescribeImageAttributeResponseTypeChoice_type0 param2 = new DescribeImageAttributeResponseTypeChoice_type0(); + + if(engineResponse.getIsPublic()){ + LaunchPermissionListType param3 = new LaunchPermissionListType(); + LaunchPermissionItemType param4 = new LaunchPermissionItemType(); + param4.setGroup("all"); + param3.addItem(param4); + param2.setLaunchPermission(param3); + }else if(engineResponse.getAccountNamesWithLaunchPermission() != null){ + LaunchPermissionListType param3 = new LaunchPermissionListType(); + for(String accountName : engineResponse.getAccountNamesWithLaunchPermission()){ + LaunchPermissionItemType param4 = new LaunchPermissionItemType(); + param4.setUserId(accountName); + param3.addItem(param4); + } + param2.setLaunchPermission(param3); + + }else if(engineResponse.getDescription() != null){ + NullableAttributeValueType param3 = new NullableAttributeValueType(); + param3.setValue( engineResponse.getDescription()); + param2.setDescription( param3 ); + } + + + param1.setDescribeImageAttributeResponseTypeChoice_type0( param2 ); + param1.setImageId(engineResponse.getImageId()); + } + + param1.setRequestId( UUID.randomUUID().toString()); + response.setDescribeImageAttributeResponse( param1 ); + return response; + } + + public static ModifyImageAttributeResponse toModifyImageAttributeResponse( boolean engineResponse ) { ModifyImageAttributeResponse response = new ModifyImageAttributeResponse(); ModifyImageAttributeResponseType param1 = new ModifyImageAttributeResponseType(); diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeImageAttribute.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeImageAttribute.java new file mode 100644 index 00000000000..3ccb35ab245 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeImageAttribute.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.cloud.bridge.service.core.ec2; + + + +import com.cloud.bridge.service.core.ec2.EC2ImageAttributes.ImageAttribute; + +public class EC2DescribeImageAttribute { + + private String imageId = null; //AMI id + private ImageAttribute attribute = null; + + public EC2DescribeImageAttribute() { + } + + public void setAttribute(ImageAttribute attribute) { + this.attribute = attribute; + } + + public ImageAttribute getAttribute() { + return attribute; + } + + public void setImageId(String imageId) { + this.imageId = imageId; + } + + public String getImageId() { + return imageId; + } + +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java index 2eec930810a..5aa0c0a7344 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -31,11 +31,14 @@ import java.util.UUID; import javax.xml.parsers.ParserConfigurationException; import org.apache.log4j.Logger; +import org.hibernate.ejb.criteria.expression.UnaryArithmeticOperation.Operation; import org.xml.sax.SAXException; import com.cloud.bridge.persist.dao.CloudStackSvcOfferingDao; import com.cloud.bridge.persist.dao.OfferingDao; import com.cloud.bridge.service.UserContext; + +import com.cloud.bridge.service.core.ec2.EC2ImageAttributes.ImageAttribute; import com.cloud.bridge.service.exception.EC2ServiceException; import com.cloud.bridge.service.exception.EC2ServiceException.ClientError; import com.cloud.bridge.service.exception.EC2ServiceException.ServerError; @@ -59,6 +62,7 @@ import com.cloud.stack.models.CloudStackSecurityGroupIngress; import com.cloud.stack.models.CloudStackServiceOffering; import com.cloud.stack.models.CloudStackSnapshot; import com.cloud.stack.models.CloudStackTemplate; +import com.cloud.stack.models.CloudStackTemplatePermission; import com.cloud.stack.models.CloudStackUser; import com.cloud.stack.models.CloudStackUserVm; import com.cloud.stack.models.CloudStackVolume; @@ -518,6 +522,34 @@ public class EC2Engine { throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred."); } } + + + /** REST API calls this method. + * Modify an existing template + * + * @param request + * @return + */ + public boolean modifyImageAttribute( EC2Image request ) + { + // TODO: This is incomplete + EC2DescribeImagesResponse images = new EC2DescribeImagesResponse(); + + try { + images = listTemplates( request.getId(), images ); + EC2Image[] imageSet = images.getImageSet(); + + CloudStackTemplate resp = getApi().updateTemplate(request.getId(), null, request.getDescription(), null, imageSet[0].getName(), null, null); + if (resp != null) { + return true; + } + return false; + } catch( Exception e ) { + logger.error( "EC2 ModifyImage - ", e); + throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); + } + } + /** * Modify an existing template @@ -525,25 +557,87 @@ public class EC2Engine { * @param request * @return */ - public boolean modifyImageAttribute( EC2Image request ) + public boolean modifyImageAttribute( EC2ModifyImageAttribute request ) { - // TODO: This is incomplete - EC2DescribeImagesResponse images = new EC2DescribeImagesResponse(); + try { + if(request.getAttribute().equals(ImageAttribute.launchPermission)){ + + String accounts = ""; + Boolean isPublic = null; + EC2ModifyImageAttribute.Operation operation = request.getLaunchPermOperation(); + + List accountOrGroupList = request.getLaunchPermissionAccountsList(); + if(accountOrGroupList != null && !accountOrGroupList.isEmpty()){ + boolean first = true; + for(String accountOrGroup : accountOrGroupList){ + if("all".equalsIgnoreCase(accountOrGroup)){ + if(operation.equals(EC2ModifyImageAttribute.Operation.add)){ + isPublic = true; + }else{ + isPublic = false; + } + }else{ + if(!first){ + accounts = accounts + ","; + } + accounts = accounts + accountOrGroup; + first = false; + } + } + } + CloudStackInfoResponse resp = getApi().updateTemplatePermissions(request.getImageId(), accounts, null, null, isPublic, operation.toString()); + return resp.getSuccess(); + }else if(request.getAttribute().equals(ImageAttribute.description)){ + CloudStackTemplate resp = getApi().updateTemplate(request.getImageId(), null, request.getDescription(), null, null, null, null); + if (resp != null) { + return true; + } + return false; + } - try { - images = listTemplates( request.getId(), images ); - EC2Image[] imageSet = images.getImageSet(); - - CloudStackTemplate resp = getApi().updateTemplate(request.getId(), null, request.getDescription(), null, imageSet[0].getName(), null, null); - if (resp != null) { - return true; - } - return false; - } catch( Exception e ) { - logger.error( "EC2 ModifyImage - ", e); - throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); - } + } catch (Exception e) { + logger.error( "EC2 modifyImageAttribute - ", e); + throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); + } + + return false; + + } + + public EC2ImageAttributes describeImageAttribute(EC2DescribeImageAttribute request) { + EC2ImageAttributes imageAtts = new EC2ImageAttributes(); + + try { + imageAtts.setImageId(request.getImageId()); + if(request.getAttribute().equals(ImageAttribute.launchPermission)){ + CloudStackTemplatePermission tempPerm = getApi().listTemplatePermissions(request.getImageId(), null, null); + if(tempPerm != null){ + imageAtts.setDomainId(tempPerm.getDomainId()); + + List accntList = tempPerm.getAccounts(); + imageAtts.setAccountNamesWithLaunchPermission(accntList); + + imageAtts.setIsPublic(tempPerm.getIsPublic()); + } + }else if(request.getAttribute().equals(ImageAttribute.description)){ + EC2DescribeImagesResponse descriptionResp = new EC2DescribeImagesResponse(); + listTemplates(request.getImageId(), descriptionResp); + if(descriptionResp.getImageSet() != null){ + EC2Image[] images = descriptionResp.getImageSet(); + imageAtts.setDescription(images[0].getDescription()); + } + } + + } catch (Exception e) { + logger.error( "EC2 describeImageAttribute - ", e); + throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); + } + + return imageAtts; + } + + /** * If given a specific list of snapshots of interest, then only values from those snapshots are returned. diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ImageAttributes.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ImageAttributes.java new file mode 100644 index 00000000000..5444c85e0f9 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ImageAttributes.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.cloud.bridge.service.core.ec2; + +import java.util.List; + +public class EC2ImageAttributes { + + private String imageId; + private String description; + private boolean isPublic; + private List accountNamesWithLaunchPermission; + private String domainId; + + public enum ImageAttribute{ + description, + launchPermission, + kernel, + ramdisk, + productCodes, + blockDeviceMapping + }; + + public EC2ImageAttributes() { + imageId = null; + description = null; + isPublic = false; + accountNamesWithLaunchPermission= null; + domainId = null; + } + + public void setImageId( String imageId ) { + this.imageId = imageId; + } + + public String getImageId() { + return this.imageId; + } + + public void setDescription( String description ) { + this.description = description; + } + + public String getDescription() { + return this.description; + } + + public void setIsPublic( boolean isPublic ) { + this.isPublic = isPublic; + } + + public boolean getIsPublic() { + return this.isPublic; + } + + + public String getDomainId() { + return domainId; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public void setAccountNamesWithLaunchPermission(List accountNamesWithLaunchPermission) { + this.accountNamesWithLaunchPermission = accountNamesWithLaunchPermission; + } + + public List getAccountNamesWithLaunchPermission() { + return accountNamesWithLaunchPermission; + } + +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ModifyImageAttribute.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ModifyImageAttribute.java new file mode 100644 index 00000000000..4fc93923143 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ModifyImageAttribute.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.cloud.bridge.service.core.ec2; + + +import java.util.List; + +import com.cloud.bridge.service.core.ec2.EC2ImageAttributes.ImageAttribute; + +public class EC2ModifyImageAttribute { + + private String imageId = null; //AMI id + private ImageAttribute attribute = null; + private String description; + private Boolean isPublic = null; + + private Operation launchPermOperation = null; + public enum Operation{ + add, + remove, + reset; + } + + private List launchPermissionAccountsOrGroupList; + + public EC2ModifyImageAttribute() { + } + + + public void setAttribute(ImageAttribute attribute) { + this.attribute = attribute; + } + + public ImageAttribute getAttribute() { + return attribute; + } + + public void setImageId(String imageId) { + this.imageId = imageId; + } + + public String getImageId() { + return imageId; + } + + public void setDescription( String description ) { + this.description = description; + } + + public String getDescription() { + return this.description; + } + + public void setLaunchPermissionAccountsOrGroupList(List launchPermissionAccountsOrGroupList) { + this.launchPermissionAccountsOrGroupList = launchPermissionAccountsOrGroupList; + } + + public List getLaunchPermissionAccountsList() { + return launchPermissionAccountsOrGroupList; + } + + public void setLaunchPermOperation( Operation launchPermOperation ) { + this.launchPermOperation = launchPermOperation; + } + + public Operation getLaunchPermOperation() { + return this.launchPermOperation; + } + + + public void setIsPublic(Boolean isPublic) { + this.isPublic = isPublic; + } + + + public Boolean getIsPublic() { + return isPublic; + } + + +} diff --git a/awsapi/src/com/cloud/stack/CloudStackApi.java b/awsapi/src/com/cloud/stack/CloudStackApi.java index 73d261cae38..d4e7703d6a5 100644 --- a/awsapi/src/com/cloud/stack/CloudStackApi.java +++ b/awsapi/src/com/cloud/stack/CloudStackApi.java @@ -566,15 +566,15 @@ public class CloudStackApi { * @return * @throws Exception */ - public List listTemplatePermissions(String id, String account, String domainId) throws Exception { + public CloudStackTemplatePermission listTemplatePermissions(String id, String account, String domainId) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_TEMPLATE_PERMISSIONS); if (cmd != null) { cmd.setParam(ApiConstants.ID, id); if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); if (domainId != null) cmd.setParam(ApiConstants.DOMAIN_ID, domainId); } - return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_TEMPLATE_PERMISSIONS_RESPONSE, ApiConstants.TEMPLATE_PERMISSION, - new TypeToken>() {}.getType()); + return _client.call(cmd, apiKey, secretKey, false, ApiConstants.LIST_TEMPLATE_PERMISSIONS_RESPONSE, ApiConstants.TEMPLATE_PERMISSION, + CloudStackTemplatePermission.class); } /** diff --git a/awsapi/src/com/cloud/stack/models/CloudStackTemplatePermission.java b/awsapi/src/com/cloud/stack/models/CloudStackTemplatePermission.java index 888ac951c26..d627dadfaed 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackTemplatePermission.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackTemplatePermission.java @@ -26,13 +26,13 @@ import com.google.gson.annotations.SerializedName; */ public class CloudStackTemplatePermission { @SerializedName(ApiConstants.ID) - private Long id; + private String id; @SerializedName(ApiConstants.IS_PUBLIC) private Boolean isPublic; @SerializedName(ApiConstants.DOMAIN_ID) - private Long domainId; + private String domainId; @SerializedName(ApiConstants.ACCOUNT) - private List accounts; + private List accounts; /** @@ -45,7 +45,7 @@ public class CloudStackTemplatePermission { /** * @return the id */ - public Long getId() { + public String getId() { return id; } @@ -61,7 +61,7 @@ public class CloudStackTemplatePermission { /** * @return the domainId */ - public Long getDomainId() { + public String getDomainId() { return domainId; } @@ -69,7 +69,7 @@ public class CloudStackTemplatePermission { /** * @return the accounts */ - public List getAccounts() { + public List getAccounts() { return accounts; } From 3d4ccc0a96f7081dea8c4bc43e41e2ee6cb9772b Mon Sep 17 00:00:00 2001 From: prachi Date: Mon, 7 May 2012 11:38:55 -0700 Subject: [PATCH 05/13] CloudStack listTemplatePermissions should add the owner of the template to the list of users having launchPermissions. If the template is Public, we need not add the owner explicitly. --- server/src/com/cloud/template/TemplateManagerImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 6aead480dd3..1b648a040c7 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -1296,6 +1296,11 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe accountNames.add(acct.getAccountName()); } } + //also add the owner if not public + if(!template.isPublicTemplate()){ + Account templateOwner = _accountDao.findById(template.getAccountId()); + accountNames.add(templateOwner.getAccountName()); + } return accountNames; } From dcbd098ab07a6832a50386792831b65dafe2da33 Mon Sep 17 00:00:00 2001 From: prachi Date: Mon, 7 May 2012 12:43:11 -0700 Subject: [PATCH 06/13] CS-14777- Not able to retrieve password of a VM using ec2-get-password command. Resolved. The response parsing in awsapi was broken. --- awsapi/src/com/cloud/stack/CloudStackApi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awsapi/src/com/cloud/stack/CloudStackApi.java b/awsapi/src/com/cloud/stack/CloudStackApi.java index d4e7703d6a5..70e109080e0 100644 --- a/awsapi/src/com/cloud/stack/CloudStackApi.java +++ b/awsapi/src/com/cloud/stack/CloudStackApi.java @@ -348,7 +348,7 @@ public class CloudStackApi { if (cmd != null) cmd.setParam(ApiConstants.ID, id); // TODO: This probably isn't right. Need to test with an instance that has a VM Password - return _client.call(cmd, apiKey, secretKey, true, ApiConstants.GET_VM_PASSWORD_RESPONSE, null, CloudStackPasswordData.class); + return _client.call(cmd, apiKey, secretKey, true, ApiConstants.GET_VM_PASSWORD_RESPONSE, ApiConstants.PASSWORD, CloudStackPasswordData.class); } // Templates From 2dff3e74226b7f4c0873057bf97a54330bd92061 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 7 May 2012 14:03:46 -0700 Subject: [PATCH 07/13] cloudstack 3.0 UI - log out - error handling - not reload the current document when onLogoutCallback() return false --- ui/scripts/cloudStack.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index b7101d79c68..1b6637dfd0b 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -317,15 +317,14 @@ $.cookie('timezone', null); $.cookie('supportELB', null); - if(onLogoutCallback()) { //set g_loginResponse(single-sign-on variable) to null, then bypassLoginCheck() will show login screen. - document.location.reload(); + if(onLogoutCallback()) { //onLogoutCallback() will set g_loginResponse(single-sign-on variable) to null, then bypassLoginCheck() will show login screen. + document.location.reload(); //when onLogoutCallback() returns true, reload the current document. } }, error: function() { - if(onLogoutCallback()) { //set g_loginResponse(single-sign-on variable) to null, then bypassLoginCheck() will show login screen. - document.location.reload(); - } - document.location.reload(); + if(onLogoutCallback()) { //onLogoutCallback() will set g_loginResponse(single-sign-on variable) to null, then bypassLoginCheck() will show login screen. + document.location.reload(); //when onLogoutCallback() returns true, reload the current document. + } }, beforeSend : function(XMLHttpResponse) { return true; From da884e18ef561e73c383513eae389a2848786f36 Mon Sep 17 00:00:00 2001 From: prachi Date: Mon, 7 May 2012 14:31:01 -0700 Subject: [PATCH 08/13] CS-14775: When trying to vms when there is enough capacity for only Vms between the min and max range , we donot respect the min count. Changes: Deploy minimum instances if the max allowed is less than the specified max. number in the request. --- awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java index 5aa0c0a7344..f187efa7820 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -1377,7 +1377,7 @@ public class EC2Engine { } if ( canCreateInstances < request.getMaxCount()) - createInstances = canCreateInstances; + createInstances = request.getMinCount(); else createInstances = request.getMaxCount(); From 99f88eff3206f48ba4826f60936344155f60b257 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 7 May 2012 14:59:46 -0700 Subject: [PATCH 09/13] cloudstack 3.0 UI - single sign on - provide example code to log out to a different location instead of the login page. --- ui/scripts/cloud.core.callbacks.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ui/scripts/cloud.core.callbacks.js b/ui/scripts/cloud.core.callbacks.js index bcaa0fe128e..505b739115d 100644 --- a/ui/scripts/cloud.core.callbacks.js +++ b/ui/scripts/cloud.core.callbacks.js @@ -23,10 +23,14 @@ the session ID has been changed (i.e. another user logging into the UI via a dif or it's the first time the user has come to this page. */ function onLogoutCallback() { - // Returning true means the LOGIN page will be show. If you wish to redirect the user - // to different login page, this is where you would do that. - g_loginResponse = null; - return true; + g_loginResponse = null; //clear single signon variable g_loginResponse + + + return true; // return true means the login page will show + /* + window.location.replace("http://www.google.com"); //redirect to a different location + return false; //return false means it will stay in the location window.location.replace() sets it to (i.e. "http://www.google.com") + */ } var g_loginResponse = null; From 3d0811ecb71d4fab979ade184960a23335a5618d Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 7 May 2012 15:38:26 -0700 Subject: [PATCH 10/13] cloudstack 3.0 UI - IP Address page - listView - remove dummy filter. --- ui/scripts/network.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 0abba2efe24..bd111001b88 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -899,11 +899,7 @@ title: 'label.menu.ipaddresses', listView: { id: 'ipAddresses', - label: 'IPs', - filters: { - allocated: { label: 'label.allocated' }, - mine: { label: 'label.my.network' } - }, + label: 'IPs', fields: { ipaddress: { label: 'IP', From 4c163bfab0fa9af877f496ccc492db98d9addb94 Mon Sep 17 00:00:00 2001 From: prachi Date: Mon, 7 May 2012 16:06:17 -0700 Subject: [PATCH 11/13] CS-14687: When a valid instance id that does not belong to the current user is passed to ec2-stop-instances,ec2-start-instances,ec2-terminate-instances, api does not return anythin Changes: Throw error if LookUpInstances fails to list the Vm by id. --- awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java index f187efa7820..cf2639c1f5f 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -1795,6 +1795,11 @@ public class EC2Engine { } instances.addInstance(ec2Vm); } + }else{ + if(instanceId != null){ + //no such instance found + throw new EC2ServiceException(ServerError.InternalError, "Instance:" + instanceId + " not found"); + } } return instances; } From 0ca7bbe89faa134acb40f22df8fad5d4befac59b Mon Sep 17 00:00:00 2001 From: prachi Date: Mon, 7 May 2012 17:21:15 -0700 Subject: [PATCH 12/13] CS-14682 - When invalid filter name is provided in ec2-describe-instances command , java.lang.reflect.InvocationTargetException is thrown. Changes: - AxisFault was not being constructed in some cases --- .../src/com/cloud/bridge/service/EC2SoapServiceImpl.java | 9 +++++---- .../bridge/service/core/ec2/EC2InstanceFilterSet.java | 4 ++-- .../bridge/service/exception/EC2ServiceException.java | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java index 0f0e309db88..6958248a5c8 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java +++ b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java @@ -81,6 +81,7 @@ import com.cloud.bridge.service.core.ec2.EC2Volume; import com.cloud.bridge.service.core.ec2.EC2VolumeFilterSet; import com.cloud.bridge.service.exception.EC2ServiceException; import com.cloud.bridge.service.exception.EC2ServiceException.ClientError; +import com.cloud.bridge.service.exception.EC2ServiceException.ServerError; import com.cloud.bridge.util.EC2RestAuth; @@ -247,7 +248,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { request.setAttribute(ImageAttribute.launchPermission); return toDescribeImageAttributeResponse( engine.describeImageAttribute( request )); } - else throw new EC2ServiceException( "Unsupported - only description or launchPermission supported", 501 ); + else throw new EC2ServiceException( ClientError.Unsupported, "Unsupported - only description or launchPermission supported" ); } @@ -292,7 +293,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { request.addInstanceId( diat.getInstanceId()); return toDescribeInstanceAttributeResponse( engine.describeInstances( request )); } - throw new EC2ServiceException( "Unsupported - only instanceType supported", 501 ); + throw new EC2ServiceException( ClientError.Unsupported, "Unsupported - only instanceType supported"); } @@ -484,7 +485,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { } return toModifyImageAttributeResponse( engine.modifyImageAttribute( request )); } - throw new EC2ServiceException( "Unsupported - can only modify image description or launchPermission", 501 ); + throw new EC2ServiceException( ClientError.Unsupported, "Unsupported - can only modify image description or launchPermission"); } private void setAccountOrGroupList(LaunchPermissionItemType[] items, EC2ModifyImageAttribute request){ @@ -586,7 +587,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { request.setLaunchPermOperation(EC2ModifyImageAttribute.Operation.reset); return toResetImageAttributeResponse( engine.modifyImageAttribute( request )); } - throw new EC2ServiceException( "Unsupported - can only reset image launchPermission", 501 ); + throw new EC2ServiceException( ClientError.Unsupported, "Unsupported - can only reset image launchPermission" ); } /** diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java index 8cd697c9b6f..d0a44de0e0b 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java @@ -55,10 +55,10 @@ public class EC2InstanceFilterSet { String value = (String) filterTypes.get( filterName ); if (null == value) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); + throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); if (null != value && value.equalsIgnoreCase( "null" )) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); + throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); // ToDo we could add checks to make sure the type of a filters value is correct (e.g., an integer) filterSet.add( param ); diff --git a/awsapi/src/com/cloud/bridge/service/exception/EC2ServiceException.java b/awsapi/src/com/cloud/bridge/service/exception/EC2ServiceException.java index de6446a7c2f..8b26d61d40c 100644 --- a/awsapi/src/com/cloud/bridge/service/exception/EC2ServiceException.java +++ b/awsapi/src/com/cloud/bridge/service/exception/EC2ServiceException.java @@ -29,7 +29,7 @@ public class EC2ServiceException extends RuntimeException { InsufficientInstanceCapacity("Server.InsufficientInstanceCapacity", 500), InsufficientReservedInstanceCapacity("Server.InsufficientReservedInstanceCapacity", 500), InternalError("Server.InternalError", 500), - Unavailable("Server.Unavailable", 500); + Unavailable("Server.Unavailable", 501); private String errorString; private int httpErrorCode; @@ -126,7 +126,7 @@ public class EC2ServiceException extends RuntimeException { } public EC2ServiceException(String message, int errorCode) { - super(message); + super(message, new AxisFault(message, new QName("Error"))); this.httpErrorCode = errorCode; } From 5e87559558836163e0fdbd7ac31ca463921bb05d Mon Sep 17 00:00:00 2001 From: prachi Date: Mon, 7 May 2012 18:15:14 -0700 Subject: [PATCH 13/13] Adding changes for awsapi to tomcat conf. - Need to open port 7080 using different threadpool for loopback requests from awsapi to cloudstack --- client/tomcatconf/server-nonssl.xml | 9 +++++++++ client/tomcatconf/server-ssl.xml.in | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/client/tomcatconf/server-nonssl.xml b/client/tomcatconf/server-nonssl.xml index 6eba083c116..0b627b228cd 100755 --- a/client/tomcatconf/server-nonssl.xml +++ b/client/tomcatconf/server-nonssl.xml @@ -54,6 +54,8 @@ +