/* * Copyright 2011 Cloud.com, Inc. * * 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.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import com.cloud.bridge.service.exception.EC2ServiceException; import com.cloud.bridge.util.DateHelper; import com.cloud.bridge.util.EC2RestAuth; public class EC2VolumeFilterSet { protected List<EC2Filter> filterSet = new ArrayList<EC2Filter>(); private Map<String,String> filterTypes = new HashMap<String,String>(); public EC2VolumeFilterSet() { // -> use these values to check that the proper filter is passed to this type of filter set filterTypes.put( "attachment.attach-time", "xsd:dateTime" ); filterTypes.put( "attachment.delete-on-termination", "null" ); filterTypes.put( "attachment.device", "string" ); filterTypes.put( "attachment.instance-id", "string" ); filterTypes.put( "attachment.status", "null" ); filterTypes.put( "availability-zone", "string" ); filterTypes.put( "create-time", "xsd:dateTime" ); 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( "volume-id", "string" ); // filterTypes.put( "tag:*", "null" ); } 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 ); // ToDo we could add checks to make sure the type of a filters value is correct (e.g., an integer) filterSet.add( param ); } public EC2Filter[] getFilterSet() { return filterSet.toArray(new EC2Filter[0]); } /** * For a filter to match a volume just one of its values has to match the volume. * For a volume to be included in the volume response it must pass all the defined filters. * * @param sampleList - list of volumes to test against the defined filters * @return EC2DescribeVolumeResponse * @throws ParseException */ public EC2DescribeVolumesResponse evaluate( EC2DescribeVolumesResponse sampleList ) throws ParseException { EC2DescribeVolumesResponse resultList = new EC2DescribeVolumesResponse(); boolean matched; EC2Volume[] volumeSet = sampleList.getVolumeSet(); EC2Filter[] filterSet = getFilterSet(); for (EC2Volume vol : volumeSet) { matched = true; for (EC2Filter filter : filterSet) { if (!filterMatched( vol, filter )) { matched = false; break; } } if (matched) resultList.addVolume( vol ); } return resultList; } private boolean filterMatched( EC2Volume vol, EC2Filter filter ) throws ParseException { String filterName = filter.getName(); String[] valueSet = filter.getValueSet(); if ( filterName.equalsIgnoreCase( "availability-zone" )) return containsString( vol.getZoneName(), valueSet ); else if (filterName.equalsIgnoreCase( "create-time" )) return containsTime(vol.getCreated(), valueSet ); else if (filterName.equalsIgnoreCase( "size" )) return containsLong(vol.getSize(), valueSet ); else if (filterName.equalsIgnoreCase( "snapshot-id" )) return containsString(String.valueOf(vol.getSnapshotId()), valueSet ); else if (filterName.equalsIgnoreCase( "status" )) return containsString(vol.getState(), valueSet ); else if (filterName.equalsIgnoreCase( "volume-id" )) return containsString(vol.getId().toString(), valueSet ); else if (filterName.equalsIgnoreCase( "attachment.attach-time" )) return containsTime(vol.getAttached(), valueSet ); 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 ); else return false; } private boolean containsString( String lookingFor, String[] set ) { if (null == lookingFor) return false; for (String s : set) { if (lookingFor.matches( s )) return true; } return false; } private boolean containsLong( long lookingFor, String[] set ) { for (String s : set) { int temp = Integer.parseInt( s ); if (lookingFor == temp) return true; } return false; } private boolean containsTime(String lookingForDate, String[] set ) throws ParseException { Calendar lookingFor = EC2RestAuth.parseDateString(lookingForDate); for (String s : set) { Calendar toMatch = Calendar.getInstance(); toMatch.setTime( DateHelper.parseISO8601DateString( s )); if (0 == lookingFor.compareTo( toMatch )) return true; } return false; } private boolean containsDevice(String deviceId, String[] set ) { if (deviceId == null) return false; Integer devId = new Integer(deviceId); for (String s : set) { switch( devId ) { case 1: if (( "/dev/sdb" ).matches( s )) return true; if (( "/dev/xvdb").matches( s )) return true; break; case 2: if (( "/dev/sdc" ).matches( s )) return true; if (( "/dev/xvdc" ).matches( s )) return true; break; case 4: if (( "/dev/sde" ).matches( s )) return true; if (( "/dev/xvde" ).matches( s )) return true; break; case 5: if (( "/dev/sdf" ).matches( s )) return true; if (( "/dev/xvdf" ).matches( s )) return true; break; case 6: if (( "/dev/sdg" ).matches( s )) return true; if (( "/dev/xvdg" ).matches( s )) return true; break; case 7: if (( "/dev/sdh" ).matches( s )) return true; if (( "/dev/xvdh" ).matches( s )) return true; break; case 8: if (( "/dev/sdi" ).matches( s )) return true; if (( "/dev/xvdi" ).matches( s )) return true; break; case 9: if (( "/dev/sdj" ).matches( s )) return true; if (( "/dev/xvdj" ).matches( s )) return true; break; } } return false; } }