mirror of https://github.com/apache/cloudstack.git
Merge pull request #42 from shapeblue/fr13-annotations
annotations (on hosts)
This commit is contained in:
commit
3caef4487e
|
|
@ -0,0 +1,40 @@
|
|||
// 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.annotation;
|
||||
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
public interface Annotation extends InternalIdentity, Identity {
|
||||
|
||||
String getAnnotation();
|
||||
|
||||
String getEntityUuid();
|
||||
|
||||
AnnotationService.EntityType getEntityType();
|
||||
|
||||
String getUserUuid();
|
||||
|
||||
Date getCreated();
|
||||
|
||||
Date getRemoved();
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// 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.annotation;
|
||||
|
||||
import org.apache.cloudstack.api.command.admin.annotation.AddAnnotationCmd;
|
||||
import org.apache.cloudstack.api.command.admin.annotation.ListAnnotationsCmd;
|
||||
import org.apache.cloudstack.api.command.admin.annotation.RemoveAnnotationCmd;
|
||||
import org.apache.cloudstack.api.response.AnnotationResponse;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
public interface AnnotationService {
|
||||
ListResponse<AnnotationResponse> searchForAnnotations(ListAnnotationsCmd cmd);
|
||||
|
||||
AnnotationResponse addAnnotation(AddAnnotationCmd addAnnotationCmd);
|
||||
AnnotationResponse addAnnotation(String text, EntityType type, String uuid);
|
||||
|
||||
AnnotationResponse removeAnnotation(RemoveAnnotationCmd removeAnnotationCmd);
|
||||
|
||||
enum EntityType {
|
||||
HOST("host"), DOMAIN("domain"), VM("vm_instance");
|
||||
private String tableName;
|
||||
|
||||
EntityType(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ public class ApiConstants {
|
|||
public static final String ADDRESS = "address";
|
||||
public static final String ALGORITHM = "algorithm";
|
||||
public static final String ALLOCATED_ONLY = "allocatedonly";
|
||||
public static final String ANNOTATION = "annotation";
|
||||
public static final String API_KEY = "apikey";
|
||||
public static final String USER_API_KEY = "userapikey";
|
||||
public static final String APPLIED = "applied";
|
||||
|
|
@ -637,6 +638,8 @@ public class ApiConstants {
|
|||
public static final String PHYSICAL_SIZE = "physicalsize";
|
||||
public static final String VIRTUAL_SIZE = "virtualsize";
|
||||
public static final String UTILIZATION = "utilization";
|
||||
public static final String HAS_ANNOTATION = "hasannotation";
|
||||
public static final String LAST_ANNOTATED = "lastannotated";
|
||||
|
||||
public enum HostDetails {
|
||||
all, capacity, events, stats, min;
|
||||
|
|
|
|||
|
|
@ -17,32 +17,6 @@
|
|||
|
||||
package org.apache.cloudstack.api;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.utils.HttpUtils;
|
||||
import org.apache.cloudstack.acl.RoleService;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.affinity.AffinityGroupService;
|
||||
import org.apache.cloudstack.alert.AlertService;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
|
||||
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
|
||||
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
|
||||
import org.apache.cloudstack.query.QueryService;
|
||||
import org.apache.cloudstack.usage.UsageService;
|
||||
|
||||
import com.cloud.configuration.ConfigurationService;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
|
|
@ -78,11 +52,35 @@ import com.cloud.user.Account;
|
|||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.DomainService;
|
||||
import com.cloud.user.ResourceLimitService;
|
||||
import com.cloud.utils.HttpUtils;
|
||||
import com.cloud.utils.ReflectUtil;
|
||||
import com.cloud.utils.db.EntityManager;
|
||||
import com.cloud.utils.db.UUIDManager;
|
||||
import com.cloud.vm.UserVmService;
|
||||
import com.cloud.vm.snapshot.VMSnapshotService;
|
||||
import org.apache.cloudstack.acl.RoleService;
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.affinity.AffinityGroupService;
|
||||
import org.apache.cloudstack.alert.AlertService;
|
||||
import org.apache.cloudstack.annotation.AnnotationService;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
|
||||
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
|
||||
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
|
||||
import org.apache.cloudstack.query.QueryService;
|
||||
import org.apache.cloudstack.usage.UsageService;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class BaseCmd {
|
||||
private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName());
|
||||
|
|
@ -95,6 +93,7 @@ public abstract class BaseCmd {
|
|||
public static Pattern newInputDateFormat = Pattern.compile("[\\d]+-[\\d]+-[\\d]+ [\\d]+:[\\d]+:[\\d]+");
|
||||
private static final DateFormat s_outputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
protected static final Map<Class<?>, List<Field>> fieldsForCmdClass = new HashMap<Class<?>, List<Field>>();
|
||||
|
||||
public static enum HTTPMethod {
|
||||
GET, POST, PUT, DELETE
|
||||
}
|
||||
|
|
@ -194,6 +193,8 @@ public abstract class BaseCmd {
|
|||
public AlertService _alertSvc;
|
||||
@Inject
|
||||
public UUIDManager _uuidMgr;
|
||||
@Inject
|
||||
public AnnotationService annotationService;
|
||||
|
||||
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
|
||||
ResourceAllocationException, NetworkRuleConflictException;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
// 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.admin.annotation;
|
||||
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.NetworkRuleConflictException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.user.Account;
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.cloudstack.annotation.AnnotationService;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.AnnotationResponse;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
@APICommand(name = AddAnnotationCmd.APINAME, description = "add an annotation.", responseObject = AnnotationResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
public class AddAnnotationCmd extends BaseCmd{
|
||||
|
||||
@Parameter(name = ApiConstants.ANNOTATION, type = CommandType.STRING, description = "the annotation text")
|
||||
private String annotation;
|
||||
@Parameter(name = ApiConstants.ENTITY_TYPE, type = CommandType.STRING, description = "the entity type")
|
||||
private String entityType;
|
||||
@Parameter(name = ApiConstants.ENTITY_ID, type = CommandType.STRING, description = "the id of the entity to annotate")
|
||||
private String entityUuid;
|
||||
|
||||
public String getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
public AnnotationService.EntityType getEntityType() {
|
||||
return AnnotationService.EntityType.valueOf(entityType);
|
||||
}
|
||||
|
||||
public String getEntityUuid() {
|
||||
return entityUuid;
|
||||
}
|
||||
|
||||
public static final String APINAME = "addAnnotation";
|
||||
|
||||
@Override
|
||||
public void execute()
|
||||
throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
|
||||
NetworkRuleConflictException {
|
||||
Preconditions.checkNotNull(entityUuid,"I have to have an entity to set an annotation on!");
|
||||
AnnotationResponse annotationResponse = annotationService.addAnnotation(this);
|
||||
annotationResponse.setResponseName(getCommandName());
|
||||
this.setResponseObject(annotationResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
// for now all annotations are belong to us
|
||||
return Account.ACCOUNT_ID_SYSTEM;
|
||||
// we would of course query the owner of the actual entitytype/entityuuid to return the right account
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// 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.admin.annotation;
|
||||
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.NetworkRuleConflictException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.utils.StringUtils;
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.BaseListCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.AnnotationResponse;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
@APICommand(name = ListAnnotationsCmd.APINAME, description = "Lists annotations.", responseObject = AnnotationResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
public class ListAnnotationsCmd extends BaseListCmd {
|
||||
|
||||
public static final String APINAME = "listAnnotations";
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
public String getEntityUuid() {
|
||||
return entityUuid;
|
||||
}
|
||||
|
||||
@Parameter(name = ApiConstants.ID, type = CommandType.STRING, description = "the id of the annotation")
|
||||
private String uuid;
|
||||
@Parameter(name = ApiConstants.ENTITY_TYPE, type = CommandType.STRING, description = "the entity type")
|
||||
private String entityType;
|
||||
@Parameter(name = ApiConstants.ENTITY_ID, type = CommandType.STRING, description = "the id of the entity for which to show annotations")
|
||||
private String entityUuid;
|
||||
|
||||
@Override public void execute()
|
||||
throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
|
||||
NetworkRuleConflictException {
|
||||
// preconditions to check:
|
||||
// if entity type is null entity uuid can not have a value
|
||||
Preconditions.checkArgument(StringUtils.isNotBlank(entityType) ? ! StringUtils.isNotBlank(uuid) : true,
|
||||
"I can search for an anotation on an entity or for a specific annotation, not both");
|
||||
// if uuid has a value entity type and entity uuid can not have a value
|
||||
Preconditions.checkArgument(StringUtils.isNotBlank(uuid) ? entityType == null && entityUuid == null : true,
|
||||
"I will either search for a specific annotation or for annotations on an entity, not both");
|
||||
|
||||
ListResponse<AnnotationResponse> response = annotationService.searchForAnnotations(this);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
response.setObjectName("annotations");
|
||||
}
|
||||
|
||||
@Override public String getCommandName() {
|
||||
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// 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.admin.annotation;
|
||||
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.NetworkRuleConflictException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.user.Account;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.AnnotationResponse;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
@APICommand(name = RemoveAnnotationCmd.APINAME, description = "remove an annotation.", responseObject = AnnotationResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
public class RemoveAnnotationCmd extends BaseCmd{
|
||||
|
||||
@Parameter(name = ApiConstants.ID, type = CommandType.STRING, required = true, description = "the id of the annotation")
|
||||
private String uuid;
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public static final String APINAME = "removeAnnotation";
|
||||
|
||||
@Override
|
||||
public void execute()
|
||||
throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
|
||||
NetworkRuleConflictException {
|
||||
AnnotationResponse annotationResponse = annotationService.removeAnnotation(this);
|
||||
annotationResponse.setResponseName(getCommandName());
|
||||
this.setResponseObject(annotationResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
// for now all annotations are belong to us
|
||||
return Account.ACCOUNT_ID_SYSTEM;
|
||||
// we would of course query the owner of the actual entitytype/entityuuid to return the right account
|
||||
}
|
||||
}
|
||||
|
|
@ -16,10 +16,9 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.host;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.user.Account;
|
||||
import org.apache.cloudstack.annotation.AnnotationService;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
|
|
@ -28,9 +27,9 @@ import org.apache.cloudstack.api.Parameter;
|
|||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
|
||||
import org.apache.cloudstack.api.response.HostResponse;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.user.Account;
|
||||
import java.util.List;
|
||||
|
||||
@APICommand(name = "updateHost", description = "Updates a host.", responseObject = HostResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
|
|
@ -62,6 +61,9 @@ public class UpdateHostCmd extends BaseCmd {
|
|||
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the new uri for the secondary storage: nfs://host/path")
|
||||
private String url;
|
||||
|
||||
@Parameter(name = ApiConstants.ANNOTATION, type = CommandType.STRING, description = "Add an annotation to this host")
|
||||
private String annotation;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -86,6 +88,10 @@ public class UpdateHostCmd extends BaseCmd {
|
|||
return url;
|
||||
}
|
||||
|
||||
public String getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -109,6 +115,9 @@ public class UpdateHostCmd extends BaseCmd {
|
|||
Host result;
|
||||
try {
|
||||
result = _resourceService.updateHost(this);
|
||||
if(getAnnotation() != null) {
|
||||
annotationService.addAnnotation(getAnnotation(), AnnotationService.EntityType.HOST, result.getUuid());
|
||||
}
|
||||
HostResponse hostResponse = _responseGenerator.createHostResponse(result);
|
||||
hostResponse.setResponseName(getCommandName());
|
||||
this.setResponseObject(hostResponse);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
// 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 com.cloud.serializer.Param;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.apache.cloudstack.annotation.Annotation;
|
||||
import org.apache.cloudstack.annotation.AnnotationService;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseResponse;
|
||||
import org.apache.cloudstack.api.EntityReference;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
@EntityReference(value = Annotation.class)
|
||||
public class AnnotationResponse extends BaseResponse {
|
||||
@SerializedName(ApiConstants.ID)
|
||||
@Param(description = "the (uu)id of the annotation")
|
||||
private String uuid;
|
||||
|
||||
@SerializedName(ApiConstants.ENTITY_TYPE)
|
||||
@Param(description = "the type of the annotated entity")
|
||||
private String entityType;
|
||||
|
||||
@SerializedName(ApiConstants.ENTITY_ID)
|
||||
@Param(description = "the (uu)id of the entitiy to which this annotation pertains")
|
||||
private String entityUuid;
|
||||
|
||||
@SerializedName(ApiConstants.ANNOTATION)
|
||||
@Param(description = "the contents of the annotation")
|
||||
private String annotation;
|
||||
|
||||
@SerializedName(ApiConstants.USER_ID)
|
||||
@Param(description = "The (uu)id of the user that entered the annotation")
|
||||
private String userUuid;
|
||||
|
||||
@SerializedName(ApiConstants.CREATED)
|
||||
@Param(description = "the creation timestamp for this annotation")
|
||||
private Date created;
|
||||
|
||||
@SerializedName(ApiConstants.REMOVED)
|
||||
@Param(description = "the removal timestamp for this annotation")
|
||||
private Date removed;
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
public void setEntityType(String entityType) {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
public void setEntityType(AnnotationService.EntityType entityType) {
|
||||
this.entityType = entityType.toString();
|
||||
}
|
||||
|
||||
public String getEntityUuid() {
|
||||
return entityUuid;
|
||||
}
|
||||
|
||||
public void setEntityUuid(String entityUuid) {
|
||||
this.entityUuid = entityUuid;
|
||||
}
|
||||
|
||||
public String getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
public void setAnnotation(String annotation) {
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
public String getUserUuid() {
|
||||
return userUuid;
|
||||
}
|
||||
|
||||
public void setUserUuid(String userUuid) {
|
||||
this.userUuid = userUuid;
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public Date getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
public void setRemoved(Date removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
}
|
||||
|
|
@ -226,6 +226,17 @@ public class HostResponse extends BaseResponse {
|
|||
@Param(description = "Host details in key/value pairs.", since = "4.5")
|
||||
private Map details;
|
||||
|
||||
@SerializedName(ApiConstants.ANNOTATION)
|
||||
@Param(description = "the last annotation set on this host by an admin", since = "4.11")
|
||||
private String annotation;
|
||||
|
||||
@SerializedName(ApiConstants.LAST_ANNOTATED)
|
||||
@Param(description = "the last time this host was annotated", since = "4.11")
|
||||
private Date lastAnnotated;
|
||||
|
||||
@SerializedName(ApiConstants.USERNAME)
|
||||
@Param(description = "the admin that annotated this host", since = "4.11")
|
||||
private String username;
|
||||
|
||||
// Default visibility to support accessing the details from unit tests
|
||||
Map getDetails() {
|
||||
|
|
@ -453,6 +464,18 @@ public class HostResponse extends BaseResponse {
|
|||
this.haHost = haHost;
|
||||
}
|
||||
|
||||
public void setAnnotation(String annotation) {
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
public void setLastAnnotated(Date lastAnnotated) {
|
||||
this.lastAnnotated = lastAnnotated;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public void setDetails(Map details) {
|
||||
|
||||
if (details == null) {
|
||||
|
|
|
|||
|
|
@ -1536,6 +1536,9 @@ label.release.dedicated.cluster=Release Dedicated Cluster
|
|||
label.dedicate.host=Dedicate Host
|
||||
label.release.dedicated.host=Release Dedicated Host
|
||||
label.number.of.cpu.sockets=The Number of CPU Sockets
|
||||
label.annotation=Annotation
|
||||
label.last.annotated=Last annotated at
|
||||
label.annotated.by=Annotated by
|
||||
label.delete.ucs.manager=Delete UCS Manager
|
||||
label.blades=Blades
|
||||
label.chassis=Chassis
|
||||
|
|
|
|||
|
|
@ -348,5 +348,6 @@
|
|||
<bean id="LBStickinessPolicyDetailsDaoImpl" class="org.apache.cloudstack.resourcedetail.dao.LBStickinessPolicyDetailsDaoImpl" />
|
||||
<bean id="LBHealthCheckPolicyDetailsDaoImpl" class="org.apache.cloudstack.resourcedetail.dao.LBHealthCheckPolicyDetailsDaoImpl" />
|
||||
<bean id="outOfBandManagementDaoImpl" class="org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDaoImpl" />
|
||||
<bean id="annotationDaoImpl" class="org.apache.cloudstack.annotation.dao.AnnotationDaoImpl" />
|
||||
|
||||
</beans>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
// 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.annotation;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "annotations")
|
||||
public class AnnotationVO implements Annotation {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
|
||||
@Column(name = "uuid")
|
||||
private String uuid;
|
||||
|
||||
@Column(name = "annotation")
|
||||
private String annotation;
|
||||
|
||||
@Column(name = "entity_uuid")
|
||||
private String entityUuid;
|
||||
|
||||
@Column(name = "entity_type")
|
||||
private AnnotationService.EntityType entityType;
|
||||
|
||||
@Column(name = "user_uuid")
|
||||
private String userUuid;
|
||||
|
||||
@Column(name = GenericDao.CREATED_COLUMN)
|
||||
private Date created;
|
||||
|
||||
@Column(name = GenericDao.REMOVED_COLUMN)
|
||||
private Date removed;
|
||||
|
||||
// construct
|
||||
public AnnotationVO() {
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public AnnotationVO(String text, AnnotationService.EntityType type, String uuid) {
|
||||
this();
|
||||
setAnnotation(text);
|
||||
setEntityType(type);
|
||||
setEntityUuid(uuid);
|
||||
}
|
||||
|
||||
public AnnotationVO(String text, String type, String uuid) {
|
||||
this();
|
||||
setAnnotation(text);
|
||||
setEntityType(type);
|
||||
setEntityUuid(uuid);
|
||||
}
|
||||
// access
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityUuid() {
|
||||
return entityUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationService.EntityType getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserUuid() {
|
||||
return userUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public void setAnnotation(String annotation) {
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
public void setEntityUuid(String entityUuid) {
|
||||
this.entityUuid = entityUuid;
|
||||
}
|
||||
|
||||
public void setEntityType(String entityType) {
|
||||
this.entityType = AnnotationService.EntityType.valueOf(entityType);
|
||||
}
|
||||
|
||||
public void setEntityType(AnnotationService.EntityType entityType) {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
public void setUserUuid(String userUuid) {
|
||||
this.userUuid = userUuid;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public void setRemoved(Date removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// 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.annotation.dao;
|
||||
|
||||
import org.apache.cloudstack.annotation.AnnotationVO;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
public interface AnnotationDao extends GenericDao<AnnotationVO, Long> {
|
||||
public List<AnnotationVO> findByEntityType(String entityType);
|
||||
public List<AnnotationVO> findByEntity(String entityType, String entityUuid);
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// 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.annotation.dao;
|
||||
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import org.apache.cloudstack.annotation.AnnotationVO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @since 4.1
|
||||
*/
|
||||
@Component
|
||||
@Local(value = {AnnotationDao.class})
|
||||
public class AnnotationDaoImpl extends GenericDaoBase<AnnotationVO, Long> implements AnnotationDao {
|
||||
private final SearchBuilder<AnnotationVO> AnnotationSearchByType;
|
||||
private final SearchBuilder<AnnotationVO> AnnotationSearchByTypeAndUuid;
|
||||
|
||||
public AnnotationDaoImpl() {
|
||||
super();
|
||||
AnnotationSearchByType = createSearchBuilder();
|
||||
AnnotationSearchByType.and("entityType", AnnotationSearchByType.entity().getEntityType(), SearchCriteria.Op.EQ);
|
||||
AnnotationSearchByType.done();
|
||||
AnnotationSearchByTypeAndUuid = createSearchBuilder();
|
||||
AnnotationSearchByTypeAndUuid.and("entityType", AnnotationSearchByTypeAndUuid.entity().getEntityType(), SearchCriteria.Op.EQ);
|
||||
AnnotationSearchByTypeAndUuid.and("entityUuid", AnnotationSearchByTypeAndUuid.entity().getEntityUuid(), SearchCriteria.Op.EQ);
|
||||
AnnotationSearchByTypeAndUuid.done();
|
||||
|
||||
}
|
||||
|
||||
@Override public List<AnnotationVO> findByEntityType(String entityType) {
|
||||
SearchCriteria<AnnotationVO> sc = createSearchCriteria();
|
||||
sc.addAnd("entityType", SearchCriteria.Op.EQ, entityType);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override public List<AnnotationVO> findByEntity(String entityType, String entityUuid) {
|
||||
SearchCriteria<AnnotationVO> sc = createSearchCriteria();
|
||||
sc.addAnd("entityType", SearchCriteria.Op.EQ, entityType);
|
||||
sc.addAnd("entityUuid", SearchCriteria.Op.EQ, entityUuid);
|
||||
return listBy(sc, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -248,4 +248,7 @@
|
|||
<property name="gslbServiceProviders" value="#{gslbServiceProvidersRegistry.registered}" />
|
||||
</bean>
|
||||
<bean id="certServiceImpl" class="org.apache.cloudstack.network.lb.CertServiceImpl" />
|
||||
|
||||
<bean id="annotationService" class="org.apache.cloudstack.annotation.AnnotationManagerImpl" />
|
||||
|
||||
</beans>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,32 @@
|
|||
// under the License.
|
||||
package com.cloud.api.query.dao;
|
||||
|
||||
import com.cloud.api.ApiDBUtils;
|
||||
import com.cloud.api.query.vo.HostJoinVO;
|
||||
import com.cloud.gpu.HostGpuGroupsVO;
|
||||
import com.cloud.gpu.VGPUTypesVO;
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.host.HostStats;
|
||||
import com.cloud.host.dao.HostDetailsDao;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.storage.StorageStats;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import org.apache.cloudstack.api.ApiConstants.HostDetails;
|
||||
import org.apache.cloudstack.api.response.GpuResponse;
|
||||
import org.apache.cloudstack.api.response.HostForMigrationResponse;
|
||||
import org.apache.cloudstack.api.response.HostResponse;
|
||||
import org.apache.cloudstack.api.response.VgpuResponse;
|
||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||
import org.apache.cloudstack.ha.HAResource;
|
||||
import org.apache.cloudstack.ha.dao.HAConfigDao;
|
||||
import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.inject.Inject;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
|
@ -24,35 +50,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.host.dao.HostDetailsDao;
|
||||
import org.apache.cloudstack.ha.HAResource;
|
||||
import org.apache.cloudstack.ha.dao.HAConfigDao;
|
||||
import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants.HostDetails;
|
||||
import org.apache.cloudstack.api.response.GpuResponse;
|
||||
import org.apache.cloudstack.api.response.HostForMigrationResponse;
|
||||
import org.apache.cloudstack.api.response.HostResponse;
|
||||
import org.apache.cloudstack.api.response.VgpuResponse;
|
||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||
|
||||
import com.cloud.api.ApiDBUtils;
|
||||
import com.cloud.api.query.vo.HostJoinVO;
|
||||
import com.cloud.gpu.HostGpuGroupsVO;
|
||||
import com.cloud.gpu.VGPUTypesVO;
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.host.HostStats;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.storage.StorageStats;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
@Component
|
||||
@Local(value = {HostJoinDao.class})
|
||||
public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements HostJoinDao {
|
||||
|
|
@ -244,6 +241,9 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
|
|||
hostResponse.setJobId(host.getJobUuid());
|
||||
hostResponse.setJobStatus(host.getJobStatus());
|
||||
}
|
||||
hostResponse.setAnnotation(host.getAnnotation());
|
||||
hostResponse.setLastAnnotated(host.getLastAnnotated ());
|
||||
hostResponse.setUsername(host.getUsername());
|
||||
|
||||
hostResponse.setObjectName("host");
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,17 @@
|
|||
// under the License.
|
||||
package com.cloud.api.query.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import com.cloud.host.Host.Type;
|
||||
import com.cloud.host.Status;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.org.Cluster;
|
||||
import com.cloud.resource.ResourceState;
|
||||
import com.cloud.utils.StringUtils;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
import org.apache.cloudstack.ha.HAConfig;
|
||||
import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
|
|
@ -26,18 +36,7 @@ import javax.persistence.Id;
|
|||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
import com.cloud.host.Host.Type;
|
||||
import com.cloud.host.Status;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.org.Cluster;
|
||||
import com.cloud.resource.ResourceState;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.ha.HAConfig;
|
||||
import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Host DB view.
|
||||
|
|
@ -192,6 +191,15 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity
|
|||
@Column(name = "job_status")
|
||||
private int jobStatus;
|
||||
|
||||
@Column(name = "annotation")
|
||||
private String annotation;
|
||||
|
||||
@Column(name = "last_annotated")
|
||||
private Date lastAnnotated;
|
||||
|
||||
@Column(name = "username")
|
||||
private String username;
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return this.id;
|
||||
|
|
@ -377,4 +385,20 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity
|
|||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public String getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
public Date getLastAnnotated() {
|
||||
return lastAnnotated;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public boolean isAnnotated() {
|
||||
return StringUtils.isNotBlank(annotation);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
package org.apache.cloudstack.annotation;
|
||||
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||
import org.apache.cloudstack.api.command.admin.annotation.AddAnnotationCmd;
|
||||
import org.apache.cloudstack.api.command.admin.annotation.ListAnnotationsCmd;
|
||||
import org.apache.cloudstack.api.command.admin.annotation.RemoveAnnotationCmd;
|
||||
import org.apache.cloudstack.api.response.AnnotationResponse;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @since 4.11
|
||||
*/
|
||||
public final class AnnotationManagerImpl extends ManagerBase implements AnnotationService, PluggableService {
|
||||
public static final Logger s_logger = Logger.getLogger(AnnotationManagerImpl.class);
|
||||
|
||||
@Inject
|
||||
private AnnotationDao annotationDao;
|
||||
|
||||
@Override
|
||||
public ListResponse<AnnotationResponse> searchForAnnotations(ListAnnotationsCmd cmd) {
|
||||
List<AnnotationVO> annotations =
|
||||
getAnnotationsForApiCmd(cmd);
|
||||
List<AnnotationResponse> annotationResponses =
|
||||
convertAnnotationsToResponses(annotations);
|
||||
return createAnnotationsResponseList(annotationResponses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationResponse addAnnotation(AddAnnotationCmd addAnnotationCmd) {
|
||||
return addAnnotation(addAnnotationCmd.getAnnotation(), addAnnotationCmd.getEntityType(), addAnnotationCmd.getEntityUuid());
|
||||
}
|
||||
|
||||
public AnnotationResponse addAnnotation(String text, EntityType type, String uuid) {
|
||||
CallContext ctx = CallContext.current();
|
||||
String userUuid = ctx.getCallingUserUuid();
|
||||
|
||||
AnnotationVO annotation = new AnnotationVO(text, type, uuid);
|
||||
annotation.setUserUuid(userUuid);
|
||||
annotation = annotationDao.persist(annotation);
|
||||
return createAnnotationResponse(annotation);
|
||||
}
|
||||
|
||||
@Override public AnnotationResponse removeAnnotation(RemoveAnnotationCmd removeAnnotationCmd) {
|
||||
String uuid = removeAnnotationCmd.getUuid();
|
||||
if(s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("marking annotation removed: " + uuid);
|
||||
}
|
||||
AnnotationVO annotation = annotationDao.findByUuid(uuid);
|
||||
annotationDao.remove(annotation.getId());
|
||||
return createAnnotationResponse(annotation);
|
||||
}
|
||||
|
||||
private List<AnnotationVO> getAnnotationsForApiCmd(ListAnnotationsCmd cmd) {
|
||||
List<AnnotationVO> annotations;
|
||||
if(cmd.getUuid() != null) {
|
||||
annotations = new ArrayList<>();
|
||||
String uuid = cmd.getUuid().toString();
|
||||
if(s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("getting single annotation by uuid: " + uuid);
|
||||
}
|
||||
|
||||
annotations.add(annotationDao.findByUuid(uuid));
|
||||
} else if( ! (cmd.getEntityType() == null || cmd.getEntityType().isEmpty()) ) {
|
||||
String type = cmd.getEntityType();
|
||||
if(s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("getting annotations for type: " + type);
|
||||
}
|
||||
if (cmd.getEntityUuid() != null) {
|
||||
String uuid = cmd.getEntityUuid().toString();
|
||||
if(s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("getting annotations for entity: " + uuid);
|
||||
}
|
||||
annotations = annotationDao.findByEntity(type,cmd.getEntityUuid().toString());
|
||||
} else {
|
||||
annotations = annotationDao.findByEntityType(type);
|
||||
}
|
||||
} else {
|
||||
if(s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("getting all annotations");
|
||||
}
|
||||
annotations = annotationDao.listAll();
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
private List<AnnotationResponse> convertAnnotationsToResponses(List<AnnotationVO> annotations) {
|
||||
List<AnnotationResponse> annotationResponses = new ArrayList<>();
|
||||
for (AnnotationVO annotation : annotations) {
|
||||
annotationResponses.add(createAnnotationResponse(annotation));
|
||||
}
|
||||
return annotationResponses;
|
||||
}
|
||||
|
||||
private ListResponse<AnnotationResponse> createAnnotationsResponseList(List<AnnotationResponse> annotationResponses) {
|
||||
ListResponse<AnnotationResponse> listResponse = new ListResponse<>();
|
||||
listResponse.setResponses(annotationResponses);
|
||||
return listResponse;
|
||||
}
|
||||
|
||||
public static AnnotationResponse createAnnotationResponse(AnnotationVO annotation) {
|
||||
AnnotationResponse response = new AnnotationResponse();
|
||||
response.setUuid(annotation.getUuid());
|
||||
response.setEntityType(annotation.getEntityType());
|
||||
response.setEntityUuid(annotation.getEntityUuid());
|
||||
response.setAnnotation(annotation.getAnnotation());
|
||||
response.setUserUuid(annotation.getUserUuid());
|
||||
response.setCreated(annotation.getCreated());
|
||||
response.setRemoved(annotation.getRemoved());
|
||||
response.setObjectName("annotation");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override public List<Class<?>> getCommands() {
|
||||
final List<Class<?>> cmdList = new ArrayList<>();
|
||||
cmdList.add(AddAnnotationCmd.class);
|
||||
cmdList.add(ListAnnotationsCmd.class);
|
||||
cmdList.add(RemoveAnnotationCmd.class);
|
||||
return cmdList;
|
||||
}
|
||||
}
|
||||
|
|
@ -388,3 +388,128 @@ CREATE VIEW `cloud`.`volume_view` AS
|
|||
-- Out-of-band management driver for nested-cloudstack
|
||||
ALTER TABLE `cloud`.`oobm` MODIFY COLUMN port VARCHAR(255);
|
||||
|
||||
-- Annotations specifc changes following
|
||||
CREATE TABLE IF NOT EXISTS `cloud`.`annotations` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`uuid` varchar(40) UNIQUE,
|
||||
`annotation` text,
|
||||
`entity_uuid` varchar(40),
|
||||
`entity_type` varchar(32),
|
||||
`user_uuid` varchar(40),
|
||||
`created` datetime COMMENT 'date of creation',
|
||||
`removed` datetime COMMENT 'date of removal',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY (`uuid`),
|
||||
KEY `i_entity` (`entity_uuid`, `entity_type`, `created`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP VIEW IF EXISTS `cloud`.`last_annotation_view`;
|
||||
CREATE VIEW `last_annotation_view` AS
|
||||
SELECT
|
||||
`annotations`.`uuid` AS `uuid`,
|
||||
`annotations`.`annotation` AS `annotation`,
|
||||
`annotations`.`entity_uuid` AS `entity_uuid`,
|
||||
`annotations`.`entity_type` AS `entity_type`,
|
||||
`annotations`.`user_uuid` AS `user_uuid`,
|
||||
`annotations`.`created` AS `created`,
|
||||
`annotations`.`removed` AS `removed`
|
||||
FROM
|
||||
`annotations`
|
||||
WHERE
|
||||
`annotations`.`created` IN (SELECT
|
||||
MAX(`annotations`.`created`)
|
||||
FROM
|
||||
`annotations`
|
||||
WHERE
|
||||
`annotations`.`removed` IS NULL
|
||||
GROUP BY `annotations`.`entity_uuid`);
|
||||
|
||||
DROP VIEW IF EXISTS `cloud`.`host_view`;
|
||||
CREATE VIEW `cloud`.`host_view` AS
|
||||
SELECT
|
||||
host.id,
|
||||
host.uuid,
|
||||
host.name,
|
||||
host.status,
|
||||
host.disconnected,
|
||||
host.type,
|
||||
host.private_ip_address,
|
||||
host.version,
|
||||
host.hypervisor_type,
|
||||
host.hypervisor_version,
|
||||
host.capabilities,
|
||||
host.last_ping,
|
||||
host.created,
|
||||
host.removed,
|
||||
host.resource_state,
|
||||
host.mgmt_server_id,
|
||||
host.cpu_sockets,
|
||||
host.cpus,
|
||||
host.speed,
|
||||
host.ram,
|
||||
cluster.id cluster_id,
|
||||
cluster.uuid cluster_uuid,
|
||||
cluster.name cluster_name,
|
||||
cluster.cluster_type,
|
||||
data_center.id data_center_id,
|
||||
data_center.uuid data_center_uuid,
|
||||
data_center.name data_center_name,
|
||||
data_center.networktype data_center_type,
|
||||
host_pod_ref.id pod_id,
|
||||
host_pod_ref.uuid pod_uuid,
|
||||
host_pod_ref.name pod_name,
|
||||
host_tags.tag,
|
||||
guest_os_category.id guest_os_category_id,
|
||||
guest_os_category.uuid guest_os_category_uuid,
|
||||
guest_os_category.name guest_os_category_name,
|
||||
mem_caps.used_capacity memory_used_capacity,
|
||||
mem_caps.reserved_capacity memory_reserved_capacity,
|
||||
cpu_caps.used_capacity cpu_used_capacity,
|
||||
cpu_caps.reserved_capacity cpu_reserved_capacity,
|
||||
async_job.id job_id,
|
||||
async_job.uuid job_uuid,
|
||||
async_job.job_status job_status,
|
||||
async_job.account_id job_account_id,
|
||||
oobm.enabled AS `oobm_enabled`,
|
||||
oobm.power_state AS `oobm_power_state`,
|
||||
ha_config.enabled AS `ha_enabled`,
|
||||
ha_config.ha_state AS `ha_state`,
|
||||
ha_config.provider AS `ha_provider`,
|
||||
`last_annotation_view`.`annotation` AS `annotation`,
|
||||
`last_annotation_view`.`created` AS `last_annotated`,
|
||||
`user`.`username` AS `username`
|
||||
FROM
|
||||
`cloud`.`host`
|
||||
LEFT JOIN
|
||||
`cloud`.`cluster` ON host.cluster_id = cluster.id
|
||||
LEFT JOIN
|
||||
`cloud`.`data_center` ON host.data_center_id = data_center.id
|
||||
LEFT JOIN
|
||||
`cloud`.`host_pod_ref` ON host.pod_id = host_pod_ref.id
|
||||
LEFT JOIN
|
||||
`cloud`.`host_details` ON host.id = host_details.host_id
|
||||
AND host_details.name = 'guest.os.category.id'
|
||||
LEFT JOIN
|
||||
`cloud`.`guest_os_category` ON guest_os_category.id = CONVERT ( host_details.value, UNSIGNED )
|
||||
LEFT JOIN
|
||||
`cloud`.`host_tags` ON host_tags.host_id = host.id
|
||||
LEFT JOIN
|
||||
`cloud`.`op_host_capacity` mem_caps ON host.id = mem_caps.host_id
|
||||
AND mem_caps.capacity_type = 0
|
||||
LEFT JOIN
|
||||
`cloud`.`op_host_capacity` cpu_caps ON host.id = cpu_caps.host_id
|
||||
AND cpu_caps.capacity_type = 1
|
||||
LEFT JOIN
|
||||
`cloud`.`async_job` ON async_job.instance_id = host.id
|
||||
AND async_job.instance_type = 'Host'
|
||||
AND async_job.job_status = 0
|
||||
LEFT JOIN
|
||||
`cloud`.`oobm` ON oobm.host_id = host.id
|
||||
LEFT JOIN
|
||||
`cloud`.`ha_config` ON ha_config.resource_id= host.id
|
||||
AND ha_config.resource_type='Host'
|
||||
LEFT JOIN
|
||||
`cloud`.`last_annotation_view` ON `last_annotation_view`.`entity_uuid` = `host`.`uuid`
|
||||
LEFT JOIN
|
||||
`cloud`.`user` ON `user`.`uuid` = `last_annotation_view`.`user_uuid`;
|
||||
-- End Of Annotations specific changes
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
# 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.
|
||||
""" BVT tests for Hosts and Clusters
|
||||
"""
|
||||
#Import Local Modules
|
||||
import marvin
|
||||
from marvin.cloudstackTestCase import *
|
||||
from marvin.cloudstackAPI import *
|
||||
from marvin.lib.utils import *
|
||||
from marvin.lib.base import *
|
||||
from marvin.lib.common import *
|
||||
from marvin.lib.utils import (random_gen)
|
||||
from nose.plugins.attrib import attr
|
||||
|
||||
#Import System modules
|
||||
import time
|
||||
|
||||
_multiprocess_shared_ = True
|
||||
|
||||
class TestHostAnnotations(cloudstackTestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
self.services = self.testClient.getParsedTestDataConfig()
|
||||
self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
|
||||
self.host = list_hosts(self.apiclient,
|
||||
zoneid=self.zone.id,
|
||||
type='Routing')[0]
|
||||
self.cleanup = []
|
||||
self.added_annotations = []
|
||||
|
||||
return
|
||||
|
||||
def tearDown(self):
|
||||
try:
|
||||
#Clean up
|
||||
cleanup_resources(self.apiclient, self.cleanup)
|
||||
self.cleanAnnotations()
|
||||
except Exception as e:
|
||||
raise Exception("Warning: Exception during cleanup : %s" % e)
|
||||
return
|
||||
|
||||
def cleanAnnotations(self):
|
||||
"""Remove annotations"""
|
||||
for annotation in self.added_annotations:
|
||||
self.removeAnnotation(annotation.annotation.id)
|
||||
|
||||
def addAnnotation(self, annotation):
|
||||
cmd = addAnnotation.addAnnotationCmd()
|
||||
cmd.entityid = self.host.id
|
||||
cmd.entitytype = "HOST"
|
||||
cmd.annotation = annotation
|
||||
|
||||
self.added_annotations.append(self.apiclient.addAnnotation(cmd))
|
||||
|
||||
return self.added_annotations[-1]
|
||||
|
||||
def removeAnnotation(self, id):
|
||||
cmd = removeAnnotation.removeAnnotationCmd()
|
||||
cmd.id = id
|
||||
|
||||
return self.apiclient.removeAnnotation(cmd)
|
||||
|
||||
def getHostAnnotation(self, hostId):
|
||||
host = list_hosts(self.apiclient,
|
||||
zoneid=self.zone.id,
|
||||
type='Routing')[0]
|
||||
return host.annotation
|
||||
|
||||
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
||||
def test_01_add_annotation(self):
|
||||
"""Testing the addAnnotations API ability to add an annoatation per host"""
|
||||
self.addAnnotation("annotation1")
|
||||
self.assertEqual(self.added_annotations[-1].annotation.annotation, "annotation1")
|
||||
|
||||
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
||||
def test_02_add_multiple_annotations(self):
|
||||
"""Testing the addAnnotations API ability to add an annoatation per host
|
||||
when there are annotations already.
|
||||
And only the last one stands as annotation attribute on host level."""
|
||||
self.addAnnotation("annotation1")
|
||||
self.assertEqual(self.added_annotations[-1].annotation.annotation, "annotation1")
|
||||
|
||||
# Adds sleep of 1 second just to be sure next annotation will not be created in the same second.
|
||||
time.sleep(1)
|
||||
self.addAnnotation("annotation2")
|
||||
self.assertEqual(self.added_annotations[-1].annotation.annotation, "annotation2")
|
||||
|
||||
# Adds sleep of 1 second just to be sure next annotation will not be created in the same second.
|
||||
time.sleep(1)
|
||||
self.addAnnotation("annotation3")
|
||||
self.assertEqual(self.added_annotations[-1].annotation.annotation, "annotation3")
|
||||
|
||||
#Check that the last one is visible in host details
|
||||
self.assertEqual(self.getHostAnnotation(self.host.id), "annotation3")
|
||||
print
|
||||
|
||||
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
||||
def test_03_user_role_dont_see_annotations(self):
|
||||
"""Testing the annotations api are restricted to users"""
|
||||
|
||||
self.addAnnotation("annotation1")
|
||||
self.assertEqual(self.added_annotations[-1].annotation.annotation, "annotation1")
|
||||
|
||||
self.account = Account.create(
|
||||
self.apiclient,
|
||||
self.services["account"],
|
||||
)
|
||||
self.cleanup.append(self.account)
|
||||
|
||||
userApiClient = self.testClient.getUserApiClient(self.account.name, 'ROOT', 'User')
|
||||
|
||||
cmd = addAnnotation.addAnnotationCmd()
|
||||
cmd.entityid = self.host.id
|
||||
cmd.entitytype = "HOST"
|
||||
cmd.annotation = "test"
|
||||
|
||||
try:
|
||||
self.added_annotations.append(userApiClient.addAnnotation(cmd))
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
self.fail("AddAnnotation is allowed for User")
|
||||
|
||||
cmd = listAnnotations.listAnnotationsCmd()
|
||||
try:
|
||||
userApiClient.listAnnotations(cmd)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
self.fail("ListAnnotations is allowed for User")
|
||||
|
||||
cmd = removeAnnotation.removeAnnotationCmd()
|
||||
cmd.id = self.added_annotations[-1].annotation.id
|
||||
try:
|
||||
userApiClient.removeAnnotation(cmd)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
self.fail("RemoveAnnotation is allowed for User")
|
||||
|
||||
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
||||
def test_04_remove_annotations(self):
|
||||
"""Testing the deleteAnnotation API ability to delete annotation"""
|
||||
self.addAnnotation("annotation1")
|
||||
self.removeAnnotation(self.added_annotations[-1].annotation.id)
|
||||
del self.added_annotations[-1]
|
||||
|
|
@ -168,6 +168,9 @@ known_categories = {
|
|||
'StratosphereSsp' : ' Stratosphere SSP',
|
||||
'Metrics' : 'Metrics',
|
||||
'Infrastructure' : 'Metrics',
|
||||
'listAnnotations' : 'Annotations',
|
||||
'addAnnotation' : 'Annotations',
|
||||
'removeAnnotation' : 'Annotations',
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -779,6 +779,9 @@ $.extend(dictionary, {
|
|||
'label.dedicate.host': '<fmt:message key="label.dedicate.host" />',
|
||||
'label.release.dedicated.host': '<fmt:message key="label.release.dedicated.host" />',
|
||||
'label.number.of.cpu.sockets': '<fmt:message key="label.number.of.cpu.sockets" />',
|
||||
'label.annotation': '<fmt:message key="label.annotation" />',
|
||||
'label.last.annotated': '<fmt:message key="label.last.annotated" />',
|
||||
'label.annotated.by': '<fmt:message key="label.annotated.by" />',
|
||||
'label.delete.ucs.manager': '<fmt:message key="label.delete.ucs.manager" />',
|
||||
'label.blades': '<fmt:message key="label.blades" />',
|
||||
'label.chassis': '<fmt:message key="label.chassis" />',
|
||||
|
|
|
|||
|
|
@ -15741,8 +15741,11 @@
|
|||
array1.push("&hosttags=" + todb(args.data.hosttags));
|
||||
|
||||
if (args.data.oscategoryid != null && args.data.oscategoryid.length > 0)
|
||||
array1.push("&osCategoryId=" + args.data.oscategoryid);
|
||||
|
||||
array1.push("&osCategoryId=" + args.data.oscategoryid);
|
||||
|
||||
if (args.data.annotation != null && args.data.annotation.length > 0)
|
||||
array1.push("&annotation=" + args.data.annotation);
|
||||
|
||||
$.ajax({
|
||||
url: createURL("updateHost&id=" + args.context.hosts[0].id + array1.join("")),
|
||||
dataType: "json",
|
||||
|
|
@ -16749,9 +16752,20 @@
|
|||
},
|
||||
disconnected: {
|
||||
label: 'label.last.disconnected'
|
||||
},
|
||||
cpusockets: {
|
||||
label: 'label.number.of.cpu.sockets'
|
||||
},
|
||||
cpusockets: {
|
||||
label: 'label.number.of.cpu.sockets'
|
||||
},
|
||||
annotation: {
|
||||
label: 'label.annotation',
|
||||
isEditable: true
|
||||
},
|
||||
lastannotated: {
|
||||
label: 'label.last.annotated',
|
||||
converter: cloudStack.converters.toLocalDate
|
||||
},
|
||||
username: {
|
||||
label: 'label.annotated.by'
|
||||
}
|
||||
}, {
|
||||
|
||||
|
|
@ -16778,6 +16792,7 @@
|
|||
item.haprovider = item.hostha.haprovider;
|
||||
item.haenabled = item.hostha.haenable;
|
||||
}
|
||||
item.annotation = item.annotation;
|
||||
|
||||
$.ajax({
|
||||
url: createURL("listDedicatedHosts&hostid=" + args.context.hosts[0].id),
|
||||
|
|
|
|||
Loading…
Reference in New Issue