diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java index aa048b2058d..38f80c815fc 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java +++ b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java @@ -413,11 +413,10 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { if (null != items) { // -> can be empty for( int i=0; i < items.length; i++ ) request.addInstanceId( items[i].getInstanceId()); } - - if (null != fst) { - request.setFilterSet( toInstanceFilterSet( fst )); - } - + + if (null != fst) + request = toInstanceFilterSet( request, fst ); + return toDescribeInstancesResponse( engine.describeInstances( request ), engine ); } @@ -518,7 +517,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { { String[] timeFilters = new String[1]; timeFilters[0] = new String( "start-time" ); - request.setFilterSet( toSnapshotFilterSet( fst, timeFilters )); + request = toSnapshotFilterSet( request, fst, timeFilters ); } return toDescribeSnapshotsResponse(engine.handleRequest(request)); @@ -557,7 +556,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { String[] timeFilters = new String[2]; timeFilters[0] = new String( "attachment.attach-time" ); timeFilters[1] = new String( "create-time" ); - request.setFilterSet( toVolumeFilterSet( fst, timeFilters )); + request = toVolumeFilterSet( request, fst, timeFilters ); } return toDescribeVolumesResponse( engine.handleRequest( request )); @@ -1045,8 +1044,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { return vfs; } - - private EC2VolumeFilterSet toVolumeFilterSet( FilterSetType fst, String[] timeStrs ) + private EC2DescribeVolumes toVolumeFilterSet( EC2DescribeVolumes request, FilterSetType fst, String[] timeStrs ) { EC2VolumeFilterSet vfs = new EC2VolumeFilterSet(); boolean timeFilter = false; @@ -1057,73 +1055,94 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { // -> each filter can have one or more values associated with it for( int j=0; j < items.length; j++ ) { - EC2Filter oneFilter = new EC2Filter(); - String filterName = items[j].getName(); - oneFilter.setName( filterName ); - - // -> is the filter one of the xsd:dateTime filters? - timeFilter = false; - for( int m=0; m < timeStrs.length; m++ ) - { - timeFilter = filterName.equalsIgnoreCase( timeStrs[m] ); - if (timeFilter) break; - } - - ValueSetType vst = items[j].getValueSet(); - ValueType[] valueItems = vst.getItem(); - for( int k=0; k < valueItems.length; k++ ) - { - // -> time values are not encoded as regexes - if ( timeFilter ) - oneFilter.addValue( valueItems[k].getValue()); - else oneFilter.addValueEncoded( valueItems[k].getValue()); - } - vfs.addFilter( oneFilter ); - } - } - return vfs; - } + String filterName = items[j].getName(); + ValueSetType vst = items[j].getValueSet(); + ValueType[] valueItems = vst.getItem(); - - private EC2SnapshotFilterSet toSnapshotFilterSet( FilterSetType fst, String[] timeStrs ) - { - EC2SnapshotFilterSet vfs = new EC2SnapshotFilterSet(); + if (filterName.startsWith("tag:")) { + String key= filterName.split(":")[1]; + for (ValueType valueItem : valueItems) { + EC2TagKeyValue tag = new EC2TagKeyValue(); + tag.setKey(key); + tag.setValue(valueItem.getValue()); + request.addResourceTag(tag); + } + } else { + EC2Filter oneFilter = new EC2Filter(); + oneFilter.setName( filterName ); + + // -> is the filter one of the xsd:dateTime filters? + timeFilter = false; + for( int m=0; m < timeStrs.length; m++ ) { + timeFilter = filterName.equalsIgnoreCase( timeStrs[m] ); + if (timeFilter) break; + } + + for( int k=0; k < valueItems.length; k++ ) { + // -> time values are not encoded as regexes + if ( timeFilter ) + oneFilter.addValue( valueItems[k].getValue()); + else + oneFilter.addValueEncoded( valueItems[k].getValue()); + } + vfs.addFilter( oneFilter ); + } + } + request.setFilterSet(vfs); + } + return request; + } + + private EC2DescribeSnapshots toSnapshotFilterSet( EC2DescribeSnapshots request, FilterSetType fst, String[] timeStrs ) + { + EC2SnapshotFilterSet sfs = new EC2SnapshotFilterSet(); boolean timeFilter = false; - + FilterType[] items = fst.getItem(); if (null != items) { // -> each filter can have one or more values associated with it for( int j=0; j < items.length; j++ ) { - EC2Filter oneFilter = new EC2Filter(); - String filterName = items[j].getName(); - oneFilter.setName( filterName ); - - // -> is the filter one of the xsd:dateTime filters? - timeFilter = false; - for( int m=0; m < timeStrs.length; m++ ) - { - timeFilter = filterName.equalsIgnoreCase( timeStrs[m] ); - if (timeFilter) break; - } - - ValueSetType vst = items[j].getValueSet(); - ValueType[] valueItems = vst.getItem(); - for( int k=0; k < valueItems.length; k++ ) - { - // -> time values are not encoded as regexes - if ( timeFilter ) - oneFilter.addValue( valueItems[k].getValue()); - else oneFilter.addValueEncoded( valueItems[k].getValue()); - } - vfs.addFilter( oneFilter ); - } - } - return vfs; - } + String filterName = items[j].getName(); + ValueSetType vst = items[j].getValueSet(); + ValueType[] valueItems = vst.getItem(); + + if (filterName.startsWith("tag:")) { + String key= filterName.split(":")[1]; + for (ValueType valueItem : valueItems) { + EC2TagKeyValue tag = new EC2TagKeyValue(); + tag.setKey(key); + tag.setValue(valueItem.getValue()); + request.addResourceTag(tag); + } + } + else { + EC2Filter oneFilter = new EC2Filter(); + oneFilter.setName( filterName ); + + // -> is the filter one of the xsd:dateTime filters? + timeFilter = false; + for( int m=0; m < timeStrs.length; m++ ) { + timeFilter = filterName.equalsIgnoreCase( timeStrs[m] ); + if (timeFilter) break; + } + + for( int k=0; k < valueItems.length; k++ ) { + // -> time values are not encoded as regexes + if ( timeFilter ) + oneFilter.addValue( valueItems[k].getValue()); + else + oneFilter.addValueEncoded( valueItems[k].getValue()); + } + sfs.addFilter( oneFilter ); + } + } + request.setFilterSet(sfs); + } + return request; + } - // TODO make these filter set functions use generics private EC2GroupFilterSet toGroupFilterSet( FilterSetType fst ) { @@ -1151,8 +1170,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { return gfs; } - - private EC2InstanceFilterSet toInstanceFilterSet( FilterSetType fst ) + private EC2DescribeInstances toInstanceFilterSet( EC2DescribeInstances request, FilterSetType fst ) { EC2InstanceFilterSet ifs = new EC2InstanceFilterSet(); @@ -1162,22 +1180,30 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { // -> each filter can have one or more values associated with it for( int j=0; j < items.length; j++ ) { - EC2Filter oneFilter = new EC2Filter(); - String filterName = items[j].getName(); - oneFilter.setName( filterName ); - - ValueSetType vst = items[j].getValueSet(); - ValueType[] valueItems = vst.getItem(); - for( int k=0; k < valueItems.length; k++ ) - { - oneFilter.addValueEncoded( valueItems[k].getValue()); - } - ifs.addFilter( oneFilter ); - } - } - return ifs; - } + String filterName = items[j].getName(); + ValueSetType vst = items[j].getValueSet(); + ValueType[] valueItems = vst.getItem(); + if (filterName.startsWith("tag:")) { + String key= filterName.split(":")[1]; + for (ValueType valueItem : valueItems) { + EC2TagKeyValue tag = new EC2TagKeyValue(); + tag.setKey(key); + tag.setValue(valueItem.getValue()); + request.addResourceTag(tag); + } + } else { + EC2Filter oneFilter = new EC2Filter(); + oneFilter.setName( filterName ); + for( int k=0; k < valueItems.length; k++ ) + oneFilter.addValueEncoded( valueItems[k].getValue()); + ifs.addFilter( oneFilter ); + } + } + request.setFilterSet(ifs); + } + return request; + } private EC2AvailabilityZonesFilterSet toAvailabiltyZonesFilterSet( FilterSetType fst ) { EC2AvailabilityZonesFilterSet azfs = new EC2AvailabilityZonesFilterSet(); diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeInstances.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeInstances.java index e79cd9da870..145342fb8b0 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeInstances.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeInstances.java @@ -23,6 +23,7 @@ public class EC2DescribeInstances { private List instancesSet = new ArrayList(); // a list of strings identifying instances private EC2InstanceFilterSet ifs = null; + private List resourceTagSet = new ArrayList(); public EC2DescribeInstances() { } @@ -42,4 +43,12 @@ public class EC2DescribeInstances { public void setFilterSet( EC2InstanceFilterSet param ) { ifs = param; } + + public void addResourceTag( EC2TagKeyValue param ) { + resourceTagSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTagSet() { + return resourceTagSet.toArray(new EC2TagKeyValue[0]); + } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeSnapshots.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeSnapshots.java index 1bf6e3783e1..cd77fde854a 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeSnapshots.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeSnapshots.java @@ -23,6 +23,7 @@ public class EC2DescribeSnapshots { private List snapshotSet = new ArrayList(); // a list of strings identifying snapshots private EC2SnapshotFilterSet sfs = null; + private List resourceTagSet = new ArrayList(); public EC2DescribeSnapshots() { } @@ -42,4 +43,12 @@ public class EC2DescribeSnapshots { public void setFilterSet( EC2SnapshotFilterSet param ) { sfs = param; } + + public void addResourceTag( EC2TagKeyValue param ) { + resourceTagSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTagSet() { + return resourceTagSet.toArray(new EC2TagKeyValue[0]); + } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeVolumes.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeVolumes.java index 04145fa36c7..3bfd2a41027 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeVolumes.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeVolumes.java @@ -23,6 +23,7 @@ public class EC2DescribeVolumes { private List volumeSet = new ArrayList(); // a list of strings identifying volume ids private EC2VolumeFilterSet vfs = null; + private List resourceTagSet = new ArrayList(); public EC2DescribeVolumes() { } @@ -42,4 +43,12 @@ public class EC2DescribeVolumes { public void setFilterSet( EC2VolumeFilterSet param ) { vfs = param; } + + public void addResourceTag( EC2TagKeyValue param ) { + resourceTagSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTagSet() { + return resourceTagSet.toArray(new EC2TagKeyValue[0]); + } } 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 29060934778..c64a0732f67 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -418,20 +418,22 @@ public class EC2Engine { * @param request * @return */ - public EC2DescribeSnapshotsResponse handleRequest( EC2DescribeSnapshots request ) + public EC2DescribeSnapshotsResponse handleRequest( EC2DescribeSnapshots request ) { EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse(); EC2SnapshotFilterSet sfs = request.getFilterSet(); + EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet(); try { // -> query to get the volume size for each snapshot - EC2DescribeSnapshotsResponse response = listSnapshots( request.getSnapshotSet()); + EC2DescribeSnapshotsResponse response = listSnapshots( request.getSnapshotSet(), + getResourceTags(tagKeyValueSet)); if (response == null) { return new EC2DescribeSnapshotsResponse(); } EC2Snapshot[] snapshots = response.getSnapshotSet(); for (EC2Snapshot snap : snapshots) { - volumes = listVolumes(snap.getVolumeId(), null, volumes); + volumes = listVolumes(snap.getVolumeId(), null, volumes, null); EC2Volume[] volSet = volumes.getVolumeSet(); if (0 < volSet.length) snap.setVolumeSize(volSet[0].getSize()); volumes.reset(); @@ -473,7 +475,7 @@ public class EC2Engine { ec2Snapshot.setCreated(snap.getCreated()); ec2Snapshot.setVolumeId(snap.getVolumeId()); - List vols = getApi().listVolumes(null, null, null, snap.getVolumeId(), null, null, null, null, null, null, null); + List vols = getApi().listVolumes(null, null, null, snap.getVolumeId(), null, null, null, null, null, null, null, null); if(vols.size() > 0) { assert(vols.get(0).getSize() != null); @@ -630,17 +632,18 @@ public class EC2Engine { * * @param interestedShots - can be null, should be a subset of all snapshots */ - private EC2DescribeSnapshotsResponse listSnapshots( String[] interestedShots ) throws Exception { + private EC2DescribeSnapshotsResponse listSnapshots( String[] interestedShots, List resourceTagSet ) throws Exception { EC2DescribeSnapshotsResponse snapshots = new EC2DescribeSnapshotsResponse(); List cloudSnaps; if (interestedShots == null || interestedShots.length == 0) { - cloudSnaps = getApi().listSnapshots(null, null, null, null, null, null, null, null, null); + cloudSnaps = getApi().listSnapshots(null, null, null, null, null, null, null, null, null, resourceTagSet); } else { cloudSnaps = new ArrayList(); for(String id : interestedShots) { - List tmpList = getApi().listSnapshots(null, null, id, null, null, null, null, null, null); + List tmpList = getApi().listSnapshots(null, null, id, null, null, null, null, + null, null, resourceTagSet); cloudSnaps.addAll(tmpList); } } @@ -880,7 +883,7 @@ public class EC2Engine { public boolean associateAddress( EC2AssociateAddress request ) { try { CloudStackIpAddress cloudIp = getApi().listPublicIpAddresses(null, null, null, null, null, request.getPublicIp(), null, null, null).get(0); - CloudStackUserVm cloudVm = getApi().listVirtualMachines(null, null, true, null, null, null, null, request.getInstanceId(), null, null, null, null, null, null, null, null).get(0); + CloudStackUserVm cloudVm = getApi().listVirtualMachines(null, null, true, null, null, null, null, request.getInstanceId(), null, null, null, null, null, null, null, null, null).get(0); CloudStackInfoResponse resp = getApi().enableStaticNat(cloudIp.getId(), cloudVm.getId()); if (resp != null) { @@ -1005,7 +1008,7 @@ public class EC2Engine { // [A] Creating a template from a VM volume should be from the ROOT volume // Also for this to work the VM must be in a Stopped state so we 'reboot' it if its not EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse(); - volumes = listVolumes( null, request.getInstanceId(), volumes ); + volumes = listVolumes( null, request.getInstanceId(), volumes, null ); EC2Volume[] volSet = volumes.getVolumeSet(); for (EC2Volume vol : volSet) { if (vol.getType().equalsIgnoreCase( "ROOT" )) { @@ -1022,7 +1025,7 @@ public class EC2Engine { // [B] The parameters must be in sorted order for proper signature generation EC2DescribeInstancesResponse instances = new EC2DescribeInstancesResponse(); - instances = lookupInstances( request.getInstanceId(), instances ); + instances = lookupInstances( request.getInstanceId(), instances, null ); EC2Instance[] instanceSet = instances.getInstanceSet(); String templateId = instanceSet[0].getTemplateId(); @@ -1116,7 +1119,9 @@ public class EC2Engine { */ public EC2DescribeInstancesResponse describeInstances(EC2DescribeInstances request ) { try { - return listVirtualMachines( request.getInstancesSet(), request.getFilterSet()); + EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet(); + return listVirtualMachines( request.getInstancesSet(), request.getFilterSet(), + getResourceTags(tagKeyValueSet)); } catch( Exception e ) { logger.error( "EC2 DescribeInstances - " ,e); throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred."); @@ -1160,14 +1165,14 @@ public class EC2Engine { public EC2DescribeVolumesResponse handleRequest( EC2DescribeVolumes request ) { EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse(); EC2VolumeFilterSet vfs = request.getFilterSet(); - + EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet(); try { String[] volumeIds = request.getVolumeSet(); if ( 0 == volumeIds.length ){ - volumes = listVolumes( null, null, volumes ); + volumes = listVolumes( null, null, volumes, getResourceTags(tagKeyValueSet) ); } else { for (String s : volumeIds) - volumes = listVolumes(s, null, volumes ); + volumes = listVolumes(s, null, volumes, getResourceTags(tagKeyValueSet) ); } if ( null == vfs ) @@ -1408,7 +1413,7 @@ public class EC2Engine { // -> reboot is not allowed on destroyed (i.e., terminated) instances try { String[] instanceSet = request.getInstancesSet(); - EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null ); + EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null, null ); vms = previousState.getInstanceSet(); // -> send reboot requests for each found VM @@ -1545,7 +1550,7 @@ public class EC2Engine { // -> first determine the current state of each VM (becomes it previous state) try { - EC2DescribeInstancesResponse previousState = listVirtualMachines( request.getInstancesSet(), null ); + EC2DescribeInstancesResponse previousState = listVirtualMachines( request.getInstancesSet(), null, null ); vms = previousState.getInstanceSet(); // -> send start requests for each item @@ -1587,7 +1592,7 @@ public class EC2Engine { try { String[] instanceSet = request.getInstancesSet(); - EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null ); + EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null, null ); virtualMachines = previousState.getInstanceSet(); // -> send stop requests for each item @@ -1654,7 +1659,7 @@ public class EC2Engine { if (maxAllowed == -1) return -1; // no limit - EC2DescribeInstancesResponse existingVMS = listVirtualMachines( null, null ); + EC2DescribeInstancesResponse existingVMS = listVirtualMachines( null, null, null ); EC2Instance[] vmsList = existingVMS.getInstanceSet(); return (maxAllowed - vmsList.length); } else { @@ -1668,15 +1673,16 @@ public class EC2Engine { * @param virtualMachineIds - an array of instances we are interested in getting information on * @param ifs - filter out unwanted instances */ - private EC2DescribeInstancesResponse listVirtualMachines( String[] virtualMachineIds, EC2InstanceFilterSet ifs ) throws Exception + private EC2DescribeInstancesResponse listVirtualMachines( String[] virtualMachineIds, EC2InstanceFilterSet ifs, + List resourceTags ) throws Exception { EC2DescribeInstancesResponse instances = new EC2DescribeInstancesResponse(); if (null == virtualMachineIds || 0 == virtualMachineIds.length) { - instances = lookupInstances( null, instances ); + instances = lookupInstances( null, instances, resourceTags ); } else { for( int i=0; i < virtualMachineIds.length; i++ ) { - instances = lookupInstances( virtualMachineIds[i], instances ); + instances = lookupInstances( virtualMachineIds[i], instances, resourceTags ); } } @@ -1691,9 +1697,11 @@ public class EC2Engine { * @param volumeId - if interested in one specific volume, null if want to list all volumes * @param instanceId - if interested in volumes for a specific instance, null if instance is not important */ - private EC2DescribeVolumesResponse listVolumes(String volumeId, String instanceId, EC2DescribeVolumesResponse volumes)throws Exception { + private EC2DescribeVolumesResponse listVolumes(String volumeId, String instanceId, EC2DescribeVolumesResponse volumes, + List resourceTagSet)throws Exception { - List vols = getApi().listVolumes(null, null, null, volumeId, null, null, null, null, null, instanceId, null); + List vols = getApi().listVolumes(null, null, null, volumeId, null, null, null, null, null, + instanceId, null, resourceTagSet); if(vols != null && vols.size() > 0) { for(CloudStackVolume vol : vols) { EC2Volume ec2Vol = new EC2Volume(); @@ -1872,12 +1880,13 @@ public class EC2Engine { * @return the same object passed in as the "instances" parameter modified with one or more * EC2Instance objects loaded. */ - private EC2DescribeInstancesResponse lookupInstances( String instanceId, EC2DescribeInstancesResponse instances ) + private EC2DescribeInstancesResponse lookupInstances( String instanceId, EC2DescribeInstancesResponse instances, + List resourceTagSet ) throws Exception { String instId = instanceId != null ? instanceId : null; List vms = getApi().listVirtualMachines(null, null, true, null, null, null, null, - instId, null, null, null, null, null, null, null, null); + instId, null, null, null, null, null, null, null, null, resourceTagSet); if(vms != null && vms.size() > 0) { for(CloudStackUserVm cloudVm : vms) { @@ -2439,4 +2448,15 @@ public class EC2Engine { } return elementList.toString(); } + + private List getResourceTags(EC2TagKeyValue[] tagKeyValueSet) { + List resourceTags = new ArrayList(); + for (EC2TagKeyValue tagKeyValue : tagKeyValueSet) { + CloudStackKeyValue resourceTag = new CloudStackKeyValue(); + resourceTag.setKeyValue(tagKeyValue.getKey(), tagKeyValue.getValue()); + resourceTags.add(resourceTag); + } + return resourceTags; + } + } 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 6d5255ab2d8..449d89e2180 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java @@ -48,20 +48,21 @@ public class EC2InstanceFilterSet { filterTypes.put( "root-device-name", "string" ); filterTypes.put( "private-ip-address", "string" ); filterTypes.put( "group-id", "string" ); + filterTypes.put( "tag-key", "string" ); + filterTypes.put( "tag-value", "string" ); } public void addFilter( EC2Filter param ) { String filterName = param.getName(); - String value = (String) filterTypes.get( filterName ); - - if (null == value) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); - - if (null != value && value.equalsIgnoreCase( "null" )) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); + String value = (String) filterTypes.get( filterName ); + if (null == value) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); + + if (null != value && value.equalsIgnoreCase( "null" )) + 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 ); } @@ -162,6 +163,26 @@ public class EC2InstanceFilterSet { for (String group : groupSet) if (containsString(group, valueSet)) return true; return false; + } + else if (filterName.equalsIgnoreCase("tag-key")) + { + EC2TagKeyValue[] tagSet = vm.getResourceTags(); + for (EC2TagKeyValue tag : tagSet) + if (containsString(tag.getKey(), valueSet)) return true; + return false; + } + else if (filterName.equalsIgnoreCase("tag-value")) + { + EC2TagKeyValue[] tagSet = vm.getResourceTags(); + for (EC2TagKeyValue tag : tagSet) { + if (tag.getValue() == null) { + if (containsEmptyValue(valueSet)) return true; + } + else { + if (containsString(tag.getValue(), valueSet)) return true; + } + } + return false; } else return false; } @@ -178,8 +199,14 @@ public class EC2InstanceFilterSet { } return false; } - - + + private boolean containsEmptyValue( String[] set ) + { + for( int i=0; i < set.length; i++ ) + if (set[i].isEmpty()) return true; + return false; + } + private boolean containsInteger( int lookingFor, String[] set ) { for( int i=0; i < set.length; i++ ) diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2SnapshotFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2SnapshotFilterSet.java index 1c428f029cc..c2bed3ce161 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2SnapshotFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2SnapshotFilterSet.java @@ -46,20 +46,23 @@ public class EC2SnapshotFilterSet { filterTypes.put( "status", "string" ); filterTypes.put( "volume-id", "string" ); filterTypes.put( "volume-size", "string" ); + filterTypes.put( "tag-key", "string" ); + filterTypes.put( "tag-value", "string" ); } public void addFilter( EC2Filter param ) { String filterName = param.getName(); - String value = (String) filterTypes.get( filterName ); - - if (null == value) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); - - if (null != value && value.equalsIgnoreCase( "null" )) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); + if (!filterName.startsWith("tag:")) { + String value = (String) filterTypes.get( filterName ); + if (null == value) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); + + if (null != value && value.equalsIgnoreCase( "null" )) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); + } // ToDo we could add checks to make sure the type of a filters value is correct (e.g., an integer) filterSet.add( param ); } @@ -140,6 +143,26 @@ public class EC2SnapshotFilterSet { { return containsLong( snap.getVolumeSize(), valueSet ); } + else if (filterName.equalsIgnoreCase("tag-key")) + { + EC2TagKeyValue[] tagSet = snap.getResourceTags(); + for (EC2TagKeyValue tag : tagSet) + if (containsString(tag.getKey(), valueSet)) return true; + return false; + } + else if (filterName.equalsIgnoreCase("tag-value")) + { + EC2TagKeyValue[] tagSet = snap.getResourceTags(); + for (EC2TagKeyValue tag : tagSet){ + if (tag.getValue() == null) { + if (containsEmptyValue(valueSet)) return true; + } + else { + if (containsString(tag.getValue(), valueSet)) return true; + } + } + return false; + } else return false; } @@ -155,7 +178,13 @@ public class EC2SnapshotFilterSet { return false; } - + private boolean containsEmptyValue( String[] set ) + { + for( int i=0; i < set.length; i++ ) + if (set[i].isEmpty()) return true; + return false; + } + private boolean containsLong( long lookingFor, String[] set ) { for (String s : set) { diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java index 95d306f7c00..0594231413e 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java @@ -49,8 +49,8 @@ public class EC2VolumeFilterSet { filterTypes.put( "size", "integer" ); filterTypes.put( "snapshot-id", "string" ); filterTypes.put( "status", "set:creating|available|in-use|deleting|deleted|error" ); - filterTypes.put( "tag-key", "null" ); - filterTypes.put( "tag-value", "null" ); + filterTypes.put( "tag-key", "string" ); + filterTypes.put( "tag-value", "string" ); filterTypes.put( "volume-id", "string" ); // filterTypes.put( "tag:*", "null" ); } @@ -59,14 +59,13 @@ public class EC2VolumeFilterSet { public void addFilter( EC2Filter param ) { String filterName = param.getName(); - String value = (String) filterTypes.get( filterName ); + String value = (String) filterTypes.get( filterName ); - if (null == value) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); - - if (null != value && value.equalsIgnoreCase( "null" )) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); + if (null == value) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); + if (null != value && value.equalsIgnoreCase( "null" )) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); // ToDo we could add checks to make sure the type of a filters value is correct (e.g., an integer) filterSet.add( param ); } @@ -136,7 +135,27 @@ public class EC2VolumeFilterSet { else if (filterName.equalsIgnoreCase( "attachment.device" )) return containsDevice(vol.getDeviceId(), valueSet ); else if (filterName.equalsIgnoreCase( "attachment.instance-id" )) - return containsString(String.valueOf(vol.getInstanceId()), valueSet ); + return containsString(String.valueOf(vol.getInstanceId()), valueSet ); + else if (filterName.equalsIgnoreCase("tag-key")) + { + EC2TagKeyValue[] tagSet = vol.getResourceTags(); + for (EC2TagKeyValue tag : tagSet) + if (containsString(tag.getKey(), valueSet)) return true; + return false; + } + else if (filterName.equalsIgnoreCase("tag-value")) + { + EC2TagKeyValue[] tagSet = vol.getResourceTags(); + for (EC2TagKeyValue tag : tagSet){ + if (tag.getValue() == null) { + if (containsEmptyValue(valueSet)) return true; + } + else { + if (containsString(tag.getValue(), valueSet)) return true; + } + } + return false; + } else return false; } @@ -150,6 +169,12 @@ public class EC2VolumeFilterSet { return false; } + private boolean containsEmptyValue( String[] set ) + { + for( int i=0; i < set.length; i++ ) + if (set[i].isEmpty()) return true; + return false; + } private boolean containsLong( long lookingFor, String[] set ) { diff --git a/awsapi/src/com/cloud/stack/CloudStackApi.java b/awsapi/src/com/cloud/stack/CloudStackApi.java index 50b2b25af40..52c2459e072 100644 --- a/awsapi/src/com/cloud/stack/CloudStackApi.java +++ b/awsapi/src/com/cloud/stack/CloudStackApi.java @@ -314,7 +314,7 @@ public class CloudStackApi { */ public List listVirtualMachines(String account, String accountId, Boolean listAll, Boolean forVirtualNetwork, String groupId, String hostId, String hypervisor, String id, Boolean isRecursive, String keyWord, String name, String networkId, String podId, String state, String storageId, - String zoneId) throws Exception { + String zoneId, List resourceTags) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_VIRTUAL_MACHINES); if (cmd != null) { if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); @@ -333,6 +333,8 @@ public class CloudStackApi { if (state != null) cmd.setParam(ApiConstants.STATE, state); if (storageId != null) cmd.setParam(ApiConstants.STORAGE_ID, storageId); if (zoneId != null) cmd.setParam(ApiConstants.ZONE_ID, zoneId); + if (resourceTags != null && resourceTags.size() > 0) + cmd = setParams(cmd, null, null, resourceTags); } return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_VIRTUAL_MACHINES_RESPONSE, ApiConstants.VIRTUAL_MACHINE, new TypeToken>() {}.getType()); @@ -935,7 +937,7 @@ public class CloudStackApi { * @throws Exception */ public List listVolumes(String account, String domainId, String hostId, String id, Boolean isRecursive, String keyWord, String name, - String podId, String type, String virtualMachineId, String zoneId) throws Exception { + String podId, String type, String virtualMachineId, String zoneId, List resourceTags) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_VOLUMES); if (cmd != null) { if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); @@ -949,6 +951,8 @@ public class CloudStackApi { if (type != null) cmd.setParam(ApiConstants.TYPE, type); if (virtualMachineId != null) cmd.setParam(ApiConstants.VIRTUAL_MACHINE_ID, virtualMachineId); if (zoneId != null) cmd.setParam(ApiConstants.ZONE_ID, zoneId); + if (resourceTags != null && resourceTags.size() > 0) + cmd = setParams(cmd, null, null, resourceTags); } return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_VOLUMES_RESPONSE, ApiConstants.VOLUME, new TypeToken>() {}.getType()); @@ -1029,7 +1033,8 @@ public class CloudStackApi { private CloudStackCommand setParams(CloudStackCommand cmd, String resourceType, ListresourceIds, List resourceTags) { if (cmd != null) { - cmd.setParam(ApiConstants.RESOURCE_TYPE, resourceType); + if (resourceType != null) + cmd.setParam(ApiConstants.RESOURCE_TYPE, resourceType); if (resourceIds != null && resourceIds.size() > 0) { String resourceIdList = resourceIds.get(0); for (int i=1 ; i listSnapshots(String account, String domainId, String id, String intervalType, Boolean isRecursive, - String keyWord, String name, String snapshotType, String volumeId) throws Exception { + String keyWord, String name, String snapshotType, String volumeId, List resourceTags) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_SNAPSHOTS); if (cmd != null) { if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); @@ -1255,6 +1260,8 @@ public class CloudStackApi { if (name != null) cmd.setParam(ApiConstants.NAME, name); if (snapshotType != null) cmd.setParam(ApiConstants.SNAPSHOT_TYPE, snapshotType); if (volumeId != null) cmd.setParam(ApiConstants.VOLUME_ID, volumeId); + if (resourceTags != null && resourceTags.size() > 0) + cmd = setParams(cmd, null, null, resourceTags); } return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_SNAPSHOTS_RESPONSE, ApiConstants.SNAPSHOT, new TypeToken>() {}.getType());