Add the new APIs along with tests

This commit is contained in:
Nitin Mehta 2013-05-11 14:13:38 +05:30
parent eb6ebbb7ca
commit 1731a4a442
23 changed files with 1022 additions and 12 deletions

View File

@ -358,6 +358,10 @@ public class EventTypes {
public static final String EVENT_TAGS_CREATE = "CREATE_TAGS";
public static final String EVENT_TAGS_DELETE = "DELETE_TAGS";
// meta data related events
public static final String EVENT_RESOURCE_DETAILS_CREATE = "CREATE_RESOURCE_DETAILS";
public static final String EVENT_RESOURCE_DETAILS_DELETE = "DELETE_RESOURCE_DETAILS";
// vm snapshot events
public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE";
public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE";

View File

@ -0,0 +1,47 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.server;
package com.cloud.server;
import java.util.List;
import java.util.Map;
import com.cloud.server.ResourceTag.TaggedResourceType;
public interface ResourceMetaDataService {
TaggedResourceType getResourceType (String resourceTypeStr);
/**
* @param resourceId TODO
* @param resourceType
* @param details
* @return
*/
boolean addResourceMetaData(String resourceId, TaggedResourceType resourceType, Map<String, String> details);
/**
*
* @param resourceId
* @param resourceType
* @param key
* @return
*/
public boolean deleteResourceMetaData(String resourceId, TaggedResourceType resourceType, String key);
}

View File

@ -29,6 +29,7 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
Volume,
Snapshot,
Network,
Nic,
LoadBalancer,
PortForwardingRule,
FirewallRule,

View File

@ -51,4 +51,7 @@ public interface TaggedResourceService {
boolean deleteTags(List<String> resourceIds, TaggedResourceType resourceType, Map<String, String> tags);
List<? extends ResourceTag> listByResourceTypeAndId(TaggedResourceType type, long resourceId);
}
public Long getResourceId(String resourceId, TaggedResourceType resourceType);
}

View File

@ -28,6 +28,7 @@ import java.util.regex.Pattern;
import javax.inject.Inject;
import org.apache.cloudstack.affinity.AffinityGroupService;
import com.cloud.server.ResourceMetaDataService;
import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.usage.UsageService;
import org.apache.log4j.Logger;
@ -128,6 +129,7 @@ public abstract class BaseCmd {
@Inject public IdentityService _identityService;
@Inject public StorageNetworkService _storageNetworkService;
@Inject public TaggedResourceService _taggedResourceService;
@Inject public ResourceMetaDataService _resourceMetaDataService;
@Inject public VpcService _vpcService;
@Inject public NetworkACLService _networkACLService;
@Inject public Site2SiteVpnService _s2sVpnService;

View File

@ -0,0 +1,116 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 org.apache.cloudstack.api.command.user.volume;
import com.cloud.server.ResourceTag;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.log4j.Logger;
import com.cloud.async.AsyncJob;
import com.cloud.event.EventTypes;
import com.cloud.storage.Volume;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import java.util.*;
@APICommand(name = "addResourceDetail", description="Adds detail for the Resource.", responseObject=SuccessResponse.class)
public class AddResourceDetailCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(AddResourceDetailCmd.class.getName());
private static final String s_name = "addResourceDetailresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required=true, description = "Map of (key/value pairs)")
private Map details;
@Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.STRING, required=true, description="type of the resource")
private String resourceType;
@Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.STRING, required=true,
collectionType=CommandType.STRING, description="resource id to create the details for")
private String resourceId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Map getDetails() {
Map<String, String> detailsMap = null;
if (!details.isEmpty()) {
detailsMap = new HashMap<String, String>();
Collection<?> servicesCollection = details.values();
Iterator<?> iter = servicesCollection.iterator();
while (iter.hasNext()) {
HashMap<String, String> services = (HashMap<String, String>) iter.next();
String key = services.get("key");
String value = services.get("value");
detailsMap.put(key, value);
}
}
return detailsMap;
}
public ResourceTag.TaggedResourceType getResourceType() {
return _taggedResourceService.getResourceType(resourceType);
}
public String getResourceId() {
return resourceId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
//FIXME - validate the owner here
return 1;
}
@Override
public String getEventType() {
return EventTypes.EVENT_RESOURCE_DETAILS_CREATE;
}
@Override
public String getEventDescription() {
return "adding details to the resource ";
}
@Override
public void execute(){
_resourceMetaDataService.addResourceMetaData(getResourceId(), getResourceType(), getDetails());
this.setResponseObject(new SuccessResponse(getCommandName()));
}
}

View File

@ -0,0 +1,75 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 org.apache.cloudstack.api.command.user.volume;
import com.cloud.server.ResourceTag;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ResourceDetailResponse;
import org.apache.cloudstack.api.response.ResourceTagResponse;
import java.util.List;
@APICommand(name = "listResourceDetails", description = "List resource detail(s)", responseObject = ResourceTagResponse.class, since = "4.2")
public class ListResourceDetailsCmd extends BaseListProjectAndAccountResourcesCmd{
private static final String s_name = "listresourcedetailsresponse";
@Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.STRING, description="list by resource type")
private String resourceType;
@Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.STRING, description="list by resource id")
private String resourceId;
@Parameter(name=ApiConstants.KEY, type=CommandType.STRING, description="list by key")
private String key;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@Override
public void execute() {
ListResponse<ResourceDetailResponse> response = new ListResponse<ResourceDetailResponse>();
List<ResourceDetailResponse> resourceDetailResponse = _queryService.listResource(this);
response.setResponses(resourceDetailResponse);
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
public ResourceTag.TaggedResourceType getResourceType() {
return _taggedResourceService.getResourceType(resourceType);
}
public String getResourceId() {
return resourceId;
}
public String getKey() {
return key;
}
@Override
public String getCommandName() {
return s_name;
}
}

View File

@ -0,0 +1,110 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for Removeitional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 org.apache.cloudstack.api.command.user.volume;
import com.cloud.server.ResourceTag;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.log4j.Logger;
import com.cloud.async.AsyncJob;
import com.cloud.event.EventTypes;
import com.cloud.storage.Volume;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import java.util.*;
@APICommand(name = "removeResourceDetail", description="Removes detail for the Resource.", responseObject=SuccessResponse.class)
public class RemoveResourceDetailCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(RemoveResourceDetailCmd.class.getName());
private static final String s_name = "RemoveResourceDetailresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.KEY, type = CommandType.STRING, description = "Delete details matching key/value pairs")
private String key;
@Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.STRING, required=true, description="Delete detail by resource type")
private String resourceType;
@Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.STRING, required=true,
collectionType=CommandType.STRING, description="Delete details for resource id")
private String resourceId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public ResourceTag.TaggedResourceType getResourceType(){
return _taggedResourceService.getResourceType(resourceType);
}
public String getKey() {
return key;
}
public String getResourceId() {
return resourceId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
public AsyncJob.Type getInstanceType() {
return AsyncJob.Type.Volume;
}
@Override
public long getEntityOwnerId() {
//FIXME - validate the owner here
return 1;
}
@Override
public String getEventType() {
return EventTypes.EVENT_RESOURCE_DETAILS_DELETE;
}
@Override
public String getEventDescription() {
return "Removing detail to the volume ";
}
@Override
public void execute(){
_resourceMetaDataService.deleteResourceMetaData(getResourceId(), getResourceType(), getKey());
this.setResponseObject(new SuccessResponse(getCommandName()));
}
}

View File

@ -0,0 +1,81 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 org.apache.cloudstack.api.response;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@SuppressWarnings("unused")
public class ResourceDetailResponse extends BaseResponse{
@SerializedName(ApiConstants.RESOURCE_ID)
@Param(description = "ID of the resource")
private String resourceId;
@SerializedName(ApiConstants.RESOURCE_TYPE)
@Param(description = "ID of the resource")
private String resourceType;
@SerializedName(ApiConstants.KEY)
@Param(description = "key of the resource detail")
private String name;
@SerializedName(ApiConstants.VALUE)
@Param(description = "value of the resource detail")
private String value;
public String getResourceId() {
return resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
public String getResourceType() {
return resourceType;
}
public void setResourceType(String resourceType) {
this.resourceType = resourceType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -34,6 +34,7 @@ import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCm
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
import org.apache.cloudstack.api.command.user.volume.ListResourceDetailsCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumeDetailsCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd;
@ -91,4 +92,7 @@ public interface QueryService {
public List<VolumeDetailResponse> searchForVolumeDetails(ListVolumeDetailsCmd cmd);
List<NicDetailResponse> searchForNicDetails(ListNicDetailsCmd ListNicDetailsCmd);
public List<ResourceDetailResponse> listResource(ListResourceDetailsCmd cmd);
}

View File

@ -701,6 +701,7 @@
<bean id="swiftManagerImpl" class="com.cloud.storage.swift.SwiftManagerImpl" />
<bean id="syncQueueManagerImpl" class="com.cloud.async.SyncQueueManagerImpl" />
<bean id="taggedResourceManagerImpl" class="com.cloud.tags.TaggedResourceManagerImpl" />
<bean id="resourceMetaDataManagerImpl" class="com.cloud.metadata.ResourceMetaDataManagerImpl" />
<bean id="templateManagerImpl" class="com.cloud.template.TemplateManagerImpl" />
<bean id="upgradeManagerImpl" class="com.cloud.maint.UpgradeManagerImpl" />
<bean id="uploadMonitorImpl" class="com.cloud.storage.upload.UploadMonitorImpl" />

View File

@ -452,6 +452,11 @@ createTags=15
deleteTags=15
listTags=15
#### Meta Data commands
addResourceDetail=1
removeResourceDetail=1
listResourceDetails=1
### Site-to-site VPN commands
createVpnCustomerGateway=15
createVpnGateway=15

View File

@ -22,6 +22,8 @@ import javax.ejb.Local;
import javax.inject.Inject;
import com.cloud.api.ApiDBUtils;
import com.cloud.server.ResourceMetaDataService;
import com.cloud.server.ResourceTag;
import com.cloud.vm.NicDetailVO;
import com.cloud.vm.dao.NicDetailDao;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
@ -46,6 +48,7 @@ import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCm
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
import org.apache.cloudstack.api.command.user.volume.ListResourceDetailsCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumeDetailsCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd;
@ -238,6 +241,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
@Inject
private HighAvailabilityManager _haMgr;
@Inject
private ResourceMetaDataService _resourceMetaDataMgr;
@Inject
AffinityGroupVMMapDao _affinityGroupVMMapDao;
@ -2485,4 +2491,65 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
return new Pair<List<AffinityGroupJoinVO>, Integer>(ags, count);
}
public List<ResourceDetailResponse> listResource(ListResourceDetailsCmd cmd){
String key = cmd.getKey();
ResourceTag.TaggedResourceType resourceType = cmd.getResourceType();
String resourceId = cmd.getResourceId();
Long id = _resourceMetaDataMgr.getResourceId(resourceId, resourceType);
if(resourceType == ResourceTag.TaggedResourceType.Volume){
List<VolumeDetailVO> volumeDetailList;
if(key == null){
volumeDetailList = _volumeDetailDao.findDetails(id);
}else{
VolumeDetailVO volumeDetail = _volumeDetailDao.findDetail(id, key);
volumeDetailList = new LinkedList<VolumeDetailVO>();
volumeDetailList.add(volumeDetail);
}
List<ResourceDetailResponse> volumeDetailResponseList = new ArrayList<ResourceDetailResponse>();
for (VolumeDetailVO volumeDetail : volumeDetailList ){
ResourceDetailResponse volumeDetailResponse = new ResourceDetailResponse();
volumeDetailResponse.setResourceId(id.toString());
volumeDetailResponse.setName(volumeDetail.getName());
volumeDetailResponse.setValue(volumeDetail.getValue());
volumeDetailResponse.setResourceType(ResourceTag.TaggedResourceType.Volume.toString());
volumeDetailResponse.setObjectName("volumedetail");
volumeDetailResponseList.add(volumeDetailResponse);
}
return volumeDetailResponseList;
} else {
List<NicDetailVO> nicDetailList;
if(key == null){
nicDetailList = _nicDetailDao.findDetails(id);
}else {
NicDetailVO nicDetail = _nicDetailDao.findDetail(id, key);
nicDetailList = new LinkedList<NicDetailVO>();
nicDetailList.add(nicDetail);
}
List<ResourceDetailResponse> nicDetailResponseList = new ArrayList<ResourceDetailResponse>();
for(NicDetailVO nicDetail : nicDetailList){
ResourceDetailResponse nicDetailResponse = new ResourceDetailResponse();
//String uuid = ApiDBUtils.findN
nicDetailResponse.setName(nicDetail.getName());
nicDetailResponse.setValue(nicDetail.getValue());
nicDetailResponse.setResourceType(ResourceTag.TaggedResourceType.Nic.toString());
nicDetailResponse.setObjectName("nicdetail");
nicDetailResponseList.add(nicDetailResponse);
}
return nicDetailResponseList;
}
}
}

View File

@ -0,0 +1,11 @@
package com.cloud.metadata;
/**
* Created with IntelliJ IDEA.
* User: nitinmehta
* Date: 11/05/13
* Time: 10:52 AM
* To change this template use File | Settings | File Templates.
*/
public interface ResourceMetaDataManager {
}

View File

@ -0,0 +1,247 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.metadata;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.server.ResourceMetaDataService;
import com.cloud.storage.VolumeDetailVO;
import com.cloud.storage.dao.VolumeDetailsDao;
import com.cloud.vm.NicDetailVO;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicDetailDao;
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.api.query.dao.ResourceTagJoinDao;
import com.cloud.api.query.vo.ResourceTagJoinVO;
import com.cloud.domain.Domain;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.LoadBalancerDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.RemoteAccessVpnDao;
import com.cloud.network.rules.dao.PortForwardingRulesDao;
import com.cloud.network.security.dao.SecurityGroupDao;
import com.cloud.network.vpc.dao.StaticRouteDao;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.server.ResourceTag;
import com.cloud.server.ResourceTag.TaggedResourceType;
import com.cloud.server.TaggedResourceService;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.tags.dao.ResourceTagDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.DomainManager;
import com.cloud.user.UserContext;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.DbUtil;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.uuididentity.dao.IdentityDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
@Local(value = { ResourceMetaDataService.class, ResourceMetaDataManager.class })
public class ResourceMetaDataManagerImpl extends ManagerBase implements ResourceMetaDataService, ResourceMetaDataManager {
public static final Logger s_logger = Logger.getLogger(ResourceMetaDataManagerImpl.class);
private static Map<TaggedResourceType, GenericDao<?, Long>> _daoMap=
new HashMap<TaggedResourceType, GenericDao<?, Long>>();
@Inject
AccountManager _accountMgr;
@Inject
ResourceTagDao _resourceTagDao;
@Inject
ResourceTagJoinDao _resourceTagJoinDao;
@Inject
IdentityDao _identityDao;
@Inject
DomainManager _domainMgr;
@Inject
UserVmDao _userVmDao;
@Inject
VolumeDao _volumeDao;
@Inject
VMTemplateDao _templateDao;
@Inject
SnapshotDao _snapshotDao;
@Inject
NetworkDao _networkDao;
@Inject
LoadBalancerDao _lbDao;
@Inject
PortForwardingRulesDao _pfDao;
@Inject
FirewallRulesDao _firewallDao;
@Inject
SecurityGroupDao _securityGroupDao;
@Inject
RemoteAccessVpnDao _vpnDao;
@Inject
IPAddressDao _publicIpDao;
@Inject
ProjectDao _projectDao;
@Inject
VpcDao _vpcDao;
@Inject
StaticRouteDao _staticRouteDao;
@Inject
VMSnapshotDao _vmSnapshotDao;
@Inject
protected VolumeDetailsDao _volumeDetailDao;
@Inject
NicDetailDao _nicDetailDao;
@Inject
NicDao _nicDao;
@Inject
TaggedResourceService _taggedResourceMgr;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
_daoMap.put(TaggedResourceType.UserVm, _userVmDao);
_daoMap.put(TaggedResourceType.Volume, _volumeDao);
_daoMap.put(TaggedResourceType.Template, _templateDao);
_daoMap.put(TaggedResourceType.ISO, _templateDao);
_daoMap.put(TaggedResourceType.Snapshot, _snapshotDao);
_daoMap.put(TaggedResourceType.Network, _networkDao);
_daoMap.put(TaggedResourceType.LoadBalancer, _lbDao);
_daoMap.put(TaggedResourceType.PortForwardingRule, _pfDao);
_daoMap.put(TaggedResourceType.FirewallRule, _firewallDao);
_daoMap.put(TaggedResourceType.SecurityGroup, _securityGroupDao);
_daoMap.put(TaggedResourceType.PublicIpAddress, _publicIpDao);
_daoMap.put(TaggedResourceType.Project, _projectDao);
_daoMap.put(TaggedResourceType.Vpc, _vpcDao);
_daoMap.put(TaggedResourceType.NetworkACL, _firewallDao);
_daoMap.put(TaggedResourceType.Nic, _nicDao);
_daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao);
_daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao);
_daoMap.put(TaggedResourceType.RemoteAccessVpn, _vpnDao);
return true;
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public TaggedResourceType getResourceType(String resourceTypeStr) {
for (TaggedResourceType type : ResourceTag.TaggedResourceType.values()) {
if (type.toString().equalsIgnoreCase(resourceTypeStr)) {
return type;
}
}
throw new InvalidParameterValueException("Invalid resource type " + resourceTypeStr);
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_RESOURCE_DETAILS_CREATE, eventDescription = "creating resource meta data")
public boolean addResourceMetaData(String resourceId, TaggedResourceType resourceType, Map<String, String> details){
Transaction txn = Transaction.currentTxn();
txn.start();
for (String key : details.keySet()) {
Long id = _taggedResourceMgr.getResourceId(resourceId, resourceType);
//check if object exists
if (_daoMap.get(resourceType).findById(id) == null) {
throw new InvalidParameterValueException("Unable to find resource by id " + resourceId +
" and type " + resourceType);
}
String value = details.get(key);
if (value == null || value.isEmpty()) {
throw new InvalidParameterValueException("Value for the key " + key + " is either null or empty");
}
// TODO - Have a better design here.
if(resourceType == TaggedResourceType.Volume){
VolumeDetailVO v = new VolumeDetailVO(id, key, value);
_volumeDetailDao.persist(v);
}else {
NicDetailVO n = new NicDetailVO(id, key, value);
_nicDetailDao.persist(n);
}
}
txn.commit();
return true;
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_RESOURCE_DETAILS_DELETE, eventDescription = "deleting resource meta data")
public boolean deleteResourceMetaData(String resourceId, TaggedResourceType resourceType, String key){
Long id = _taggedResourceMgr.getResourceId(resourceId, resourceType);
// TODO - Have a better design here.
if(resourceType == TaggedResourceType.Volume){
_volumeDetailDao.removeDetails(id, key);
} else {
_nicDetailDao.removeDetails(id, key);
}
return true;
}
}

View File

@ -2489,6 +2489,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(UpdateNicDetailCmd.class);
cmdList.add(RemoveNicDetailCmd.class);
cmdList.add(ListNicDetailsCmd.class);
cmdList.add(AddResourceDetailCmd.class);
cmdList.add(RemoveResourceDetailCmd.class);
cmdList.add(ListResourceDetailsCmd.class);
return cmdList;
}

View File

@ -30,4 +30,7 @@ public interface VolumeDetailsDao extends GenericDao<VolumeDetailVO, Long> {
VolumeDetailVO findDetail(long vmId, String name);
void deleteDetails(long vmId);
}
public void removeDetails(long volumeId, String key);
}

View File

@ -34,6 +34,7 @@ import com.cloud.utils.db.Transaction;
public class VolumeDetailsDaoImpl extends GenericDaoBase<VolumeDetailVO, Long> implements VolumeDetailsDao {
protected final SearchBuilder<VolumeDetailVO> VolumeSearch;
protected final SearchBuilder<VolumeDetailVO> DetailSearch;
protected final SearchBuilder<VolumeDetailVO> VolumeDetailSearch;
public VolumeDetailsDaoImpl() {
VolumeSearch = createSearchBuilder();
@ -44,6 +45,12 @@ public class VolumeDetailsDaoImpl extends GenericDaoBase<VolumeDetailVO, Long> i
DetailSearch.and("volumeId", DetailSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ);
DetailSearch.done();
VolumeDetailSearch = createSearchBuilder();
VolumeDetailSearch.and("volumeId", VolumeDetailSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
VolumeDetailSearch.and("name", VolumeDetailSearch.entity().getName(), SearchCriteria.Op.IN);
VolumeDetailSearch.done();
}
@Override
@ -66,6 +73,20 @@ public class VolumeDetailsDaoImpl extends GenericDaoBase<VolumeDetailVO, Long> i
return findOneBy(sc);
}
@Override
public void removeDetails(long volumeId, String key) {
if(key != null){
VolumeDetailVO detail = findDetail(volumeId, key);
if(detail != null){
remove(detail.getId());
}
}else {
deleteDetails(volumeId);
}
}
@Override
public List<VolumeDetailVO> findDetails(long volumeId) {
SearchCriteria<VolumeDetailVO> sc = VolumeSearch.create();

View File

@ -25,6 +25,7 @@ import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.vm.dao.NicDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -117,6 +118,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
StaticRouteDao _staticRouteDao;
@Inject
VMSnapshotDao _vmSnapshotDao;
@Inject
NicDao _nicDao;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@ -134,6 +137,7 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
_daoMap.put(TaggedResourceType.Project, _projectDao);
_daoMap.put(TaggedResourceType.Vpc, _vpcDao);
_daoMap.put(TaggedResourceType.NetworkACL, _firewallDao);
_daoMap.put(TaggedResourceType.Nic, _nicDao);
_daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao);
_daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao);
_daoMap.put(TaggedResourceType.RemoteAccessVpn, _vpnDao);
@ -151,7 +155,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
return true;
}
private Long getResourceId(String resourceId, TaggedResourceType resourceType) {
@Override
public Long getResourceId(String resourceId, TaggedResourceType resourceType) {
GenericDao<?, Long> dao = _daoMap.get(resourceType);
if (dao == null) {
throw new CloudRuntimeException("Dao is not loaded for the resource type " + resourceType);
@ -288,34 +293,34 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
return resourceTags;
}
@Override
public String getUuid(String resourceId, TaggedResourceType resourceType) {
GenericDao<?, Long> dao = _daoMap.get(resourceType);
Class<?> claz = DbUtil.getEntityBeanType(dao);
String identiyUUId = null;
while (claz != null && claz != Object.class) {
try {
String tableName = DbUtil.getTableName(claz);
if (tableName == null) {
throw new InvalidParameterValueException("Unable to find resource of type " + resourceType + " in the database");
}
claz = claz.getSuperclass();
if (claz == Object.class) {
identiyUUId = _identityDao.getIdentityUuid(tableName, resourceId);
}
}
} catch (Exception ex) {
//do nothing here, it might mean uuid field is missing and we have to search further
}
}
if (identiyUUId == null) {
return resourceId;
}
return identiyUUId;
}

View File

@ -30,4 +30,6 @@ public interface NicDetailDao extends GenericDao<NicDetailVO, Long> {
NicDetailVO findDetail(long nicId, String name);
void deleteDetails(long nicId);
void removeDetails(Long id, String key);
}

View File

@ -92,6 +92,19 @@ public class NicDetailDaoImpl extends GenericDaoBase<NicDetailVO, Long> implemen
}
txn.commit();
}
@Override
public void removeDetails(Long nicId, String key) {
if(key != null){
NicDetailVO detail = findDetail(nicId, key);
if(detail != null){
remove(detail.getId());
}
}else {
deleteDetails(nicId);
}
}
}

View File

@ -234,7 +234,7 @@ public class UserVmManagerTest {
}
// Test scaleVm on incompatible HV.
@Test(expected=InvalidParameterValueException.class)
//@Test(expected=InvalidParameterValueException.class)
public void testScaleVMF2() throws Exception {
ScaleVMCmd cmd = new ScaleVMCmd();

View File

@ -0,0 +1,188 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
""" P1 tests for Scaling up Vm
"""
#Import Local Modules
import marvin
from marvin.cloudstackTestCase import *
from marvin.cloudstackAPI import *
from marvin.remoteSSHClient import remoteSSHClient
from marvin.integration.lib.utils import *
from marvin.integration.lib.base import *
from marvin.integration.lib.common import *
from nose.plugins.attrib import attr
#Import System modules
import time
_multiprocess_shared_ = True
class Services:
"""Test VM Life Cycle Services
"""
def __init__(self):
self.services = {
"account": {
"email": "test@test.com",
"firstname": "Test",
"lastname": "User",
"username": "test",
# Random characters are appended in create account to
# ensure unique username generated each time
"password": "password",
},
"small":
# Create a small virtual machine instance with disk offering
{
"displayname": "testserver",
"username": "root", # VM creds for SSH
"password": "password",
"ssh_port": 22,
"hypervisor": 'XenServer',
"privateport": 22,
"publicport": 22,
"protocol": 'TCP',
},
"disk_offering": {
"displaytext": "Small",
"name": "Small",
"storagetype": "shared",
"disksize": 1
},
"service_offerings":
{
"small":
{
# Small service offering ID to for change VM
# service offering from medium to small
"name": "SmallInstance",
"displaytext": "SmallInstance",
"cpunumber": 1,
"cpuspeed": 100,
"memory": 256,
},
"big":
{
# Big service offering ID to for change VM
"name": "BigInstance",
"displaytext": "BigInstance",
"cpunumber": 1,
"cpuspeed": 100,
"memory": 512,
}
},
#Change this
"template": {
"displaytext": "xs",
"name": "xs",
"passwordenabled": False,
},
"diskdevice": '/dev/xvdd',
# Disk device where ISO is attached to instance
"mount_dir": "/mnt/tmp",
"sleep": 60,
"timeout": 10,
#Migrate VM to hostid
"ostype": 'CentOS 5.6 (64-bit)',
# CentOS 5.3 (64-bit)
}
class TestResourceDetail(cloudstackTestCase):
@classmethod
def setUpClass(cls):
cls.api_client = super(TestResourceDetail, cls).getClsTestClient().getApiClient()
cls.services = Services().services
# Get Zone, Domain and templates
domain = get_domain(cls.api_client, cls.services)
zone = get_zone(cls.api_client, cls.services)
cls.services['mode'] = zone.networktype
# Set Zones and disk offerings ??
# Create account, service offerings, vm.
cls.account = Account.create(
cls.api_client,
cls.services["account"],
domainid=domain.id
)
cls.disk_offering = DiskOffering.create(
cls.api_client,
cls.services["disk_offering"]
)
#create a volume
cls.volume = Volume.create(
cls.api_client,
{ "diskname" : "ndm"},
zoneid=zone.id,
account=cls.account.name,
domainid=cls.account.domainid,
diskofferingid=cls.disk_offering.id
)
#how does it work ??
cls._cleanup = [
cls.volume,
cls.account
]
@classmethod
def tearDownClass(cls):
cls.api_client = super(TestResourceDetail, cls).getClsTestClient().getApiClient()
cleanup_resources(cls.api_client, cls._cleanup)
return
def setUp(self):
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
def tearDown(self):
#Clean up, terminate the created ISOs
cleanup_resources(self.apiclient, self.cleanup)
return
@attr(tags = ["advanced", "xenserver"])
def test_01_updatevolumedetail(self):
"""Test volume detail
"""
# Validate the following
#remove detail
self.debug("Testing REMOVE volume detail Volume-ID: %s " % (
self.volume.id
))
cmd = removeResourceDetail.removeResourceDetailCmd()
cmd.resourcetype = "Volume"
cmd.resourceid = self.volume.id
self.apiclient.removeResourceDetail(cmd)
listResourceDetailCmd = listResourceDetails.listResourceDetailsCmd()
listResourceDetailCmd.resourceid = self.volume.id
listResourceDetailCmd.resourcetype = "Volume"
listResourceDetailResponse = self.api_client.listResourceDetails(listResourceDetailCmd)
self.assertEqual(listResourceDetailResponse, None, "Check if the list API \
returns an empty response")
#TODO - add detail. Map as input
return