CLOUDSTACK-874: Ability to delete Events and Alerts

This feature will provide the functionality to delete or archive
the Alerts/Events.
Delete or archive alerts APIs are available only for root-admin,
delete or archive events are available for regular users.
This commit is contained in:
Sanjay Tripathi 2013-02-27 11:39:58 +05:30 committed by Min Chen
parent bd4508589b
commit f539f40e35
23 changed files with 1017 additions and 118 deletions

View File

@ -30,4 +30,5 @@ public interface Alert extends Identity, InternalIdentity {
Date getCreatedDate(); Date getCreatedDate();
Date getLastSent(); Date getLastSent();
Date getResolved(); Date getResolved();
boolean getArchived();
} }

View File

@ -40,4 +40,5 @@ public interface Event extends ControlledEntity, Identity, InternalIdentity {
String getLevel(); String getLevel();
long getStartId(); long getStartId();
String getParameters(); String getParameters();
boolean getArchived();
} }

View File

@ -29,6 +29,8 @@ import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd;
import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd; import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd;
import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd;
import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd;
import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd;
import org.apache.cloudstack.api.command.admin.resource.ListAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.ListAlertsCmd;
import org.apache.cloudstack.api.command.admin.resource.ListCapacityCmd; import org.apache.cloudstack.api.command.admin.resource.ListCapacityCmd;
import org.apache.cloudstack.api.command.admin.resource.UploadCustomCertificateCmd; import org.apache.cloudstack.api.command.admin.resource.UploadCustomCertificateCmd;
@ -40,12 +42,12 @@ import org.apache.cloudstack.api.command.admin.systemvm.UpgradeSystemVMCmd;
import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd; import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd;
import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd; import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd;
import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd; import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd;
import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd;
import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd;
import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd; import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd;
import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd; import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd;
import org.apache.cloudstack.api.command.user.iso.ListIsosCmd; import org.apache.cloudstack.api.command.user.iso.ListIsosCmd;
import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd; import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd;
import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd;
import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd;
import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd; import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd;
import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd; import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd;
import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd; import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd;
@ -55,12 +57,10 @@ import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd; import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd;
import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd;
import org.apache.cloudstack.api.command.user.volume.ExtractVolumeCmd; import org.apache.cloudstack.api.command.user.volume.ExtractVolumeCmd;
import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd;
import com.cloud.alert.Alert; import com.cloud.alert.Alert;
import com.cloud.capacity.Capacity; import com.cloud.capacity.Capacity;
import com.cloud.configuration.Configuration; import com.cloud.configuration.Configuration;
import com.cloud.dc.DataCenter;
import com.cloud.dc.Pod; import com.cloud.dc.Pod;
import com.cloud.dc.Vlan; import com.cloud.dc.Vlan;
import com.cloud.domain.Domain; import com.cloud.domain.Domain;
@ -72,8 +72,6 @@ import com.cloud.host.Host;
import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.HypervisorCapabilities; import com.cloud.hypervisor.HypervisorCapabilities;
import com.cloud.network.IpAddress; import com.cloud.network.IpAddress;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.org.Cluster; import com.cloud.org.Cluster;
import com.cloud.storage.GuestOS; import com.cloud.storage.GuestOS;
import com.cloud.storage.GuestOsCategory; import com.cloud.storage.GuestOsCategory;
@ -194,6 +192,34 @@ public interface ManagementService {
*/ */
Pair<List<? extends Alert>, Integer> searchForAlerts(ListAlertsCmd cmd); Pair<List<? extends Alert>, Integer> searchForAlerts(ListAlertsCmd cmd);
/**
* Archive alerts
* @param cmd
* @return True on success. False otherwise.
*/
boolean archiveAlerts(ArchiveAlertsCmd cmd);
/**
* Delete alerts
* @param cmd
* @return True on success. False otherwise.
*/
boolean deleteAlerts(DeleteAlertsCmd cmd);
/**
* Archive events
* @param cmd
* @return True on success. False otherwise.
*/
boolean archiveEvents(ArchiveEventsCmd cmd);
/**
* Delete events
* @param cmd
* @return True on success. False otherwise.
*/
boolean deleteEvents(DeleteEventsCmd cmd);
/** /**
* list all the capacity rows in capacity operations table * list all the capacity rows in capacity operations table
* *

View File

@ -459,6 +459,7 @@ public class ApiConstants {
public static final String UCS_BLADE_DN = "bladedn"; public static final String UCS_BLADE_DN = "bladedn";
public static final String UCS_BLADE_ID = "bladeid"; public static final String UCS_BLADE_ID = "bladeid";
public static final String VM_GUEST_IP = "vmguestip"; public static final String VM_GUEST_IP = "vmguestip";
public static final String OLDER_THAN = "olderthan";
public enum HostDetails { public enum HostDetails {
all, capacity, events, stats, min; all, capacity, events, stats, min;

View File

@ -0,0 +1,100 @@
// 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.resource;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AlertResponse;
import org.apache.cloudstack.api.response.ConditionResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.log4j.Logger;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
@APICommand(name = "archiveAlerts", description = "Archive one or more alerts.", responseObject = SuccessResponse.class)
public class ArchiveAlertsCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(ArchiveAlertsCmd.class.getName());
private static final String s_name = "archivealertsresponse";
// ///////////////////////////////////////////////////
// ////////////// API parameters /////////////////////
// ///////////////////////////////////////////////////
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AlertResponse.class,
description = "the IDs of the alerts")
private List<Long> ids;
@Parameter(name=ApiConstants.OLDER_THAN, type=CommandType.DATE, description="archive alerts older than this date (use format \"yyyy-MM-dd\")")
private Date olderThan;
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "archive by alert type")
private String type;
// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
public List<Long> getIds() {
return ids;
}
public Date getOlderThan() {
return olderThan;
}
public String getType() {
return type;
}
// ///////////////////////////////////////////////////
// ///////////// API Implementation///////////////////
// ///////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() {
if(ids == null && type == null && olderThan == null) {
throw new InvalidParameterValueException("either ids, type or olderthan must be specified");
}
boolean result = _mgr.archiveAlerts(this);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to archive Alerts, one or more parameters has invalid values");
}
}
}

View File

@ -0,0 +1,99 @@
// 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.resource;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AlertResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.log4j.Logger;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
@APICommand(name = "deleteAlerts", description = "Delete one or more alerts.", responseObject = SuccessResponse.class)
public class DeleteAlertsCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(DeleteAlertsCmd.class.getName());
private static final String s_name = "deletealertsresponse";
// ///////////////////////////////////////////////////
// ////////////// API parameters /////////////////////
// ///////////////////////////////////////////////////
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AlertResponse.class,
description = "the IDs of the alerts")
private List<Long> ids;
@Parameter(name=ApiConstants.OLDER_THAN, type=CommandType.DATE, description="delete alerts older than (including) this date (use format \"yyyy-MM-dd\")")
private Date olderThan;
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "delete by alert type")
private String type;
// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
public List<Long> getIds() {
return ids;
}
public Date getOlderThan() {
return olderThan;
}
public String getType() {
return type;
}
// ///////////////////////////////////////////////////
// ///////////// API Implementation///////////////////
// ///////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() {
if(ids == null && type == null && olderThan == null) {
throw new InvalidParameterValueException("either ids, type or olderthan must be specified");
}
boolean result = _mgr.deleteAlerts(this);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to delete Alerts, one or more parameters has invalid values");
}
}
}

View File

@ -0,0 +1,105 @@
//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.event;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AlertResponse;
import org.apache.cloudstack.api.response.EventResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.log4j.Logger;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
@APICommand(name = "archiveEvents", description = "Archive one or more events.", responseObject = SuccessResponse.class)
public class ArchiveEventsCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(ArchiveEventsCmd.class.getName());
private static final String s_name = "archiveeventsresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = EventResponse.class,
description = "the IDs of the events")
private List<Long> ids;
@Parameter(name=ApiConstants.OLDER_THAN, type=CommandType.DATE, description="archive events older than (including) this date (use format \"yyyy-MM-dd\" or the new format \"yyyy-MM-dd HH:mm:ss\")")
private Date olderThan;
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "archive by event type")
private String type;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public List<Long> getIds() {
return ids;
}
public Date getOlderThan() {
return olderThan;
}
public String getType() {
return type;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
Account account = UserContext.current().getCaller();
if (account != null) {
return account.getId();
}
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() {
if(ids == null && type == null && olderThan == null) {
throw new InvalidParameterValueException("either ids, type or olderthan must be specified");
}
boolean result = _mgr.archiveEvents(this);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to archive Events, one or more parameters has invalid values");
}
}
}

View File

@ -0,0 +1,105 @@
//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.event;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AlertResponse;
import org.apache.cloudstack.api.response.EventResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.log4j.Logger;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
@APICommand(name = "deleteEvents", description = "Delete one or more events.", responseObject = SuccessResponse.class)
public class DeleteEventsCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(DeleteEventsCmd.class.getName());
private static final String s_name = "deleteeventsresponse";
// ///////////////////////////////////////////////////
// ////////////// API parameters /////////////////////
// ///////////////////////////////////////////////////
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = EventResponse.class,
description = "the IDs of the events")
private List<Long> ids;
@Parameter(name=ApiConstants.OLDER_THAN, type=CommandType.DATE, description="delete events older than (including) this date (use format \"yyyy-MM-dd\" or the new format \"yyyy-MM-dd HH:mm:ss\")")
private Date olderThan;
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "delete by event type")
private String type;
// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
public List<Long> getIds() {
return ids;
}
public Date getOlderThan() {
return olderThan;
}
public String getType() {
return type;
}
// ///////////////////////////////////////////////////
// ///////////// API Implementation///////////////////
// ///////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
Account account = UserContext.current().getCaller();
if (account != null) {
return account.getId();
}
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() {
if(ids == null && type == null && olderThan == null) {
throw new InvalidParameterValueException("either ids, type or enddate must be specified");
}
boolean result = _mgr.deleteEvents(this);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to delete Events, one or more parameters has invalid values");
}
}
}

View File

@ -218,9 +218,13 @@ listZones=15
#### events commands #### events commands
listEvents=15 listEvents=15
listEventTypes=15 listEventTypes=15
archiveEvents=15
deleteEvents=15
#### alerts commands #### alerts commands
listAlerts=3 listAlerts=3
archiveAlerts=1
deleteAlerts=1
#### system capacity commands #### system capacity commands
listCapacity=3 listCapacity=3

View File

@ -28,9 +28,7 @@ import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import org.apache.cloudstack.api.Identity;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.api.InternalIdentity;
@Entity @Entity
@Table(name="alert") @Table(name="alert")
@ -68,16 +66,19 @@ public class AlertVO implements Alert {
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@Column(name="resolved", updatable=true, nullable=true) @Column(name="resolved", updatable=true, nullable=true)
private Date resolved; private Date resolved;
@Column(name="uuid") @Column(name="uuid")
private String uuid; private String uuid;
@Column(name="archived")
private boolean archived;
public AlertVO() { public AlertVO() {
this.uuid = UUID.randomUUID().toString(); this.uuid = UUID.randomUUID().toString();
} }
public AlertVO(Long id) { public AlertVO(Long id) {
this.id = id; this.id = id;
this.uuid = UUID.randomUUID().toString(); this.uuid = UUID.randomUUID().toString();
} }
@Override @Override
@ -103,12 +104,12 @@ public class AlertVO implements Alert {
} }
public Long getClusterId() { public Long getClusterId() {
return clusterId; return clusterId;
} }
public void setClusterId(Long clusterId) { public void setClusterId(Long clusterId) {
this.clusterId = clusterId; this.clusterId = clusterId;
} }
@Override @Override
public Long getPodId() { public Long getPodId() {
return podId; return podId;
} }
@ -164,10 +165,19 @@ public class AlertVO implements Alert {
@Override @Override
public String getUuid() { public String getUuid() {
return this.uuid; return this.uuid;
} }
public void setUuid(String uuid) { public void setUuid(String uuid) {
this.uuid = uuid; this.uuid = uuid;
}
@Override
public boolean getArchived() {
return archived;
}
public void setArchived(Boolean archived) {
this.archived = archived;
} }
} }

View File

@ -29,74 +29,75 @@ import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Transient; import javax.persistence.Transient;
import org.apache.cloudstack.api.Identity;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.api.InternalIdentity;
@Entity @Entity
@Table(name="event") @Table(name="event")
public class EventVO implements Event { public class EventVO implements Event {
@Id @Id
@GeneratedValue(strategy=GenerationType.IDENTITY) @GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id") @Column(name="id")
private long id = -1; private long id = -1;
@Column(name="type") @Column(name="type")
private String type; private String type;
@Enumerated(value=EnumType.STRING) @Enumerated(value=EnumType.STRING)
@Column(name="state") @Column(name="state")
private State state = State.Completed; private State state = State.Completed;
@Column(name="description", length=1024) @Column(name="description", length=1024)
private String description; private String description;
@Column(name=GenericDao.CREATED_COLUMN) @Column(name=GenericDao.CREATED_COLUMN)
private Date createDate; private Date createDate;
@Column(name="user_id") @Column(name="user_id")
private long userId; private long userId;
@Column(name="account_id") @Column(name="account_id")
private long accountId; private long accountId;
@Column(name="domain_id") @Column(name="domain_id")
private long domainId; private long domainId;
@Column(name="level") @Column(name="level")
private String level = LEVEL_INFO; private String level = LEVEL_INFO;
@Column(name="start_id") @Column(name="start_id")
private long startId; private long startId;
@Column(name="parameters", length=1024) @Column(name="parameters", length=1024)
private String parameters; private String parameters;
@Column(name="uuid")
private String uuid;
@Transient @Column(name="uuid")
private int totalSize; private String uuid;
public static final String LEVEL_INFO = "INFO"; @Column(name="archived")
public static final String LEVEL_WARN = "WARN"; private boolean archived;
public static final String LEVEL_ERROR = "ERROR";
@Transient
public EventVO() { private int totalSize;
this.uuid = UUID.randomUUID().toString();
} public static final String LEVEL_INFO = "INFO";
public static final String LEVEL_WARN = "WARN";
public long getId() { public static final String LEVEL_ERROR = "ERROR";
return id;
} public EventVO() {
@Override this.uuid = UUID.randomUUID().toString();
}
public long getId() {
return id;
}
@Override
public String getType() { public String getType() {
return type; return type;
} }
public void setType(String type) { public void setType(String type) {
this.type = type; this.type = type;
} }
@Override @Override
public State getState() { public State getState() {
return state; return state;
} }
@ -105,27 +106,27 @@ public class EventVO implements Event {
this.state = state; this.state = state;
} }
@Override @Override
public String getDescription() { public String getDescription() {
return description; return description;
} }
public void setDescription(String description) { public void setDescription(String description) {
this.description = description; this.description = description;
} }
@Override @Override
public Date getCreateDate() { public Date getCreateDate() {
return createDate; return createDate;
} }
public void setCreatedDate(Date createdDate) { public void setCreatedDate(Date createdDate) {
createDate = createdDate; createDate = createdDate;
} }
@Override @Override
public long getUserId() { public long getUserId() {
return userId; return userId;
} }
public void setUserId(long userId) { public void setUserId(long userId) {
this.userId = userId; this.userId = userId;
} }
@Override @Override
public long getAccountId() { public long getAccountId() {
return accountId; return accountId;
@ -165,21 +166,29 @@ public class EventVO implements Event {
this.startId = startId; this.startId = startId;
} }
@Override @Override
public String getParameters() { public String getParameters() {
return parameters; return parameters;
} }
public void setParameters(String parameters) { public void setParameters(String parameters) {
this.parameters = parameters; this.parameters = parameters;
} }
@Override
public String getUuid() {
return this.uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
@Override
public String getUuid() {
return this.uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
@Override
public boolean getArchived() {
return archived;
}
public void setArchived(Boolean archived) {
this.archived = archived;
}
} }

View File

@ -30,4 +30,9 @@ public interface EventDao extends GenericDao<EventVO, Long> {
public List<EventVO> listOlderEvents(Date oldTime); public List<EventVO> listOlderEvents(Date oldTime);
EventVO findCompletedEvent(long startId); EventVO findCompletedEvent(long startId);
public List<EventVO> listToArchiveOrDeleteEvents(List<Long> ids, String type, Date olderThan, Long accountId);
public void archiveEvents(List<EventVO> events);
} }

View File

@ -30,24 +30,34 @@ import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.SearchCriteria.Op;
@Component @Component
@Local(value={EventDao.class}) @Local(value={EventDao.class})
public class EventDaoImpl extends GenericDaoBase<EventVO, Long> implements EventDao { public class EventDaoImpl extends GenericDaoBase<EventVO, Long> implements EventDao {
public static final Logger s_logger = Logger.getLogger(EventDaoImpl.class.getName()); public static final Logger s_logger = Logger.getLogger(EventDaoImpl.class.getName());
protected final SearchBuilder<EventVO> CompletedEventSearch; protected final SearchBuilder<EventVO> CompletedEventSearch;
protected final SearchBuilder<EventVO> ToArchiveOrDeleteEventSearch;
public EventDaoImpl () {
CompletedEventSearch = createSearchBuilder();
CompletedEventSearch.and("state",CompletedEventSearch.entity().getState(),SearchCriteria.Op.EQ);
CompletedEventSearch.and("startId", CompletedEventSearch.entity().getStartId(), SearchCriteria.Op.EQ);
CompletedEventSearch.done();
}
@Override public EventDaoImpl () {
public List<EventVO> searchAllEvents(SearchCriteria<EventVO> sc, Filter filter) { CompletedEventSearch = createSearchBuilder();
return listIncludingRemovedBy(sc, filter); CompletedEventSearch.and("state",CompletedEventSearch.entity().getState(),SearchCriteria.Op.EQ);
} CompletedEventSearch.and("startId", CompletedEventSearch.entity().getStartId(), SearchCriteria.Op.EQ);
CompletedEventSearch.done();
ToArchiveOrDeleteEventSearch = createSearchBuilder();
ToArchiveOrDeleteEventSearch.and("id", ToArchiveOrDeleteEventSearch.entity().getId(), Op.IN);
ToArchiveOrDeleteEventSearch.and("type", ToArchiveOrDeleteEventSearch.entity().getType(), Op.EQ);
ToArchiveOrDeleteEventSearch.and("accountId", ToArchiveOrDeleteEventSearch.entity().getAccountId(), Op.EQ);
ToArchiveOrDeleteEventSearch.and("createDateL", ToArchiveOrDeleteEventSearch.entity().getCreateDate(), Op.LT);
ToArchiveOrDeleteEventSearch.done();
}
@Override
public List<EventVO> searchAllEvents(SearchCriteria<EventVO> sc, Filter filter) {
return listIncludingRemovedBy(sc, filter);
}
@Override @Override
public List<EventVO> listOlderEvents(Date oldTime) { public List<EventVO> listOlderEvents(Date oldTime) {
@ -55,9 +65,8 @@ public class EventDaoImpl extends GenericDaoBase<EventVO, Long> implements Event
SearchCriteria<EventVO> sc = createSearchCriteria(); SearchCriteria<EventVO> sc = createSearchCriteria();
sc.addAnd("createDate", SearchCriteria.Op.LT, oldTime); sc.addAnd("createDate", SearchCriteria.Op.LT, oldTime);
return listIncludingRemovedBy(sc, null); return listIncludingRemovedBy(sc, null);
} }
@Override @Override
public EventVO findCompletedEvent(long startId) { public EventVO findCompletedEvent(long startId) {
SearchCriteria<EventVO> sc = CompletedEventSearch.create(); SearchCriteria<EventVO> sc = CompletedEventSearch.create();
@ -65,4 +74,36 @@ public class EventDaoImpl extends GenericDaoBase<EventVO, Long> implements Event
sc.setParameters("startId", startId); sc.setParameters("startId", startId);
return findOneIncludingRemovedBy(sc); return findOneIncludingRemovedBy(sc);
} }
@Override
public List<EventVO> listToArchiveOrDeleteEvents(List<Long> ids, String type, Date olderThan, Long accountId) {
SearchCriteria<EventVO> sc = ToArchiveOrDeleteEventSearch.create();
if (ids != null) {
sc.setParameters("id", ids.toArray(new Object[ids.size()]));
}
if (type != null) {
sc.setParameters("type", type);
}
if (olderThan != null) {
sc.setParameters("createDateL", olderThan);
}
if (accountId != null) {
sc.setParameters("accountId", accountId);
}
return search(sc, null);
}
@Override
public void archiveEvents(List<EventVO> events) {
Transaction txn = Transaction.currentTxn();
txn.start();
for (EventVO event : events) {
event = lockRow(event.getId(), true);
event.setArchived(true);
update(event.getId(), event);
txn.commit();
}
txn.close();
}
} }

View File

@ -16,6 +16,9 @@
// under the License. // under the License.
package com.cloud.alert.dao; package com.cloud.alert.dao;
import java.util.Date;
import java.util.List;
import com.cloud.alert.AlertVO; import com.cloud.alert.AlertVO;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
@ -23,4 +26,8 @@ public interface AlertDao extends GenericDao<AlertVO, Long> {
AlertVO getLastAlert(short type, long dataCenterId, Long podId, Long clusterId); AlertVO getLastAlert(short type, long dataCenterId, Long podId, Long clusterId);
// This is for backward compatibility // This is for backward compatibility
AlertVO getLastAlert(short type, long dataCenterId, Long podId); AlertVO getLastAlert(short type, long dataCenterId, Long podId);
public boolean deleteAlert(List<Long> Ids, String type, Date olderThan, Long zoneId);
public boolean archiveAlert(List<Long> Ids, String type, Date olderThan, Long zoneId);
public List<AlertVO> listOlderAlerts(Date oldTime);
} }

View File

@ -16,6 +16,7 @@
// under the License. // under the License.
package com.cloud.alert.dao; package com.cloud.alert.dao;
import java.util.Date;
import java.util.List; import java.util.List;
import javax.ejb.Local; import javax.ejb.Local;
@ -25,11 +26,26 @@ import org.springframework.stereotype.Component;
import com.cloud.alert.AlertVO; import com.cloud.alert.AlertVO;
import com.cloud.utils.db.Filter; import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.Transaction;
@Component @Component
@Local(value = { AlertDao.class }) @Local(value = { AlertDao.class })
public class AlertDaoImpl extends GenericDaoBase<AlertVO, Long> implements AlertDao { public class AlertDaoImpl extends GenericDaoBase<AlertVO, Long> implements AlertDao {
protected final SearchBuilder<AlertVO> AlertSearchByIdsAndType;
public AlertDaoImpl() {
AlertSearchByIdsAndType = createSearchBuilder();
AlertSearchByIdsAndType.and("id", AlertSearchByIdsAndType.entity().getId(), Op.IN);
AlertSearchByIdsAndType.and("type", AlertSearchByIdsAndType.entity().getType(), Op.EQ);
AlertSearchByIdsAndType.and("createdDateL", AlertSearchByIdsAndType.entity().getCreatedDate(), Op.LT);
AlertSearchByIdsAndType.and("data_center_id", AlertSearchByIdsAndType.entity().getDataCenterId(), Op.EQ);
AlertSearchByIdsAndType.done();
}
@Override @Override
public AlertVO getLastAlert(short type, long dataCenterId, Long podId, Long clusterId) { public AlertVO getLastAlert(short type, long dataCenterId, Long podId, Long clusterId) {
Filter searchFilter = new Filter(AlertVO.class, "createdDate", Boolean.FALSE, Long.valueOf(0), Long.valueOf(1)); Filter searchFilter = new Filter(AlertVO.class, "createdDate", Boolean.FALSE, Long.valueOf(0), Long.valueOf(1));
@ -68,4 +84,73 @@ public class AlertDaoImpl extends GenericDaoBase<AlertVO, Long> implements Alert
} }
return null; return null;
} }
@Override
public boolean archiveAlert(List<Long> Ids, String type, Date olderThan, Long zoneId) {
SearchCriteria<AlertVO> sc = AlertSearchByIdsAndType.create();
if (Ids != null) {
sc.setParameters("id", Ids.toArray(new Object[Ids.size()]));
}
if(type != null) {
sc.setParameters("type", type);
}
if(zoneId != null) {
sc.setParameters("data_center_id", zoneId);
}
if(olderThan != null) {
sc.setParameters("createdDateL", olderThan);
}
boolean result = true;;
List<AlertVO> alerts = listBy(sc);
if (Ids != null && alerts.size() < Ids.size()) {
result = false;
return result;
}
Transaction txn = Transaction.currentTxn();
txn.start();
for (AlertVO alert : alerts) {
alert = lockRow(alert.getId(), true);
alert.setArchived(true);
update(alert.getId(), alert);
txn.commit();
}
txn.close();
return result;
}
@Override
public boolean deleteAlert(List<Long> ids, String type, Date olderThan, Long zoneId) {
SearchCriteria<AlertVO> sc = AlertSearchByIdsAndType.create();
if (ids != null) {
sc.setParameters("id", ids.toArray(new Object[ids.size()]));
}
if(type != null) {
sc.setParameters("type", type);
}
if(zoneId != null) {
sc.setParameters("data_center_id", zoneId);
}
if(olderThan != null) {
sc.setParameters("createdDateL", olderThan);
}
boolean result = true;
List<AlertVO> alerts = listBy(sc);
if (ids != null && alerts.size() < ids.size()) {
result = false;
return result;
}
remove(sc);
return result;
}
@Override
public List<AlertVO> listOlderAlerts(Date oldTime) {
if (oldTime == null) return null;
SearchCriteria<AlertVO> sc = createSearchCriteria();
sc.addAnd("createDate", SearchCriteria.Op.LT, oldTime);
return listIncludingRemovedBy(sc, null);
}
} }

View File

@ -50,6 +50,8 @@ import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.Validate; import org.apache.cloudstack.api.Validate;
import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd;
import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd;
import org.apache.cloudstack.api.command.user.event.ListEventsCmd; import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -391,7 +393,7 @@ public class ApiDispatcher {
// This piece of code is for maintaining backward compatibility // This piece of code is for maintaining backward compatibility
// and support both the date formats(Bug 9724) // and support both the date formats(Bug 9724)
// Do the date messaging for ListEventsCmd only // Do the date messaging for ListEventsCmd only
if (cmdObj instanceof ListEventsCmd) { if (cmdObj instanceof ListEventsCmd || cmdObj instanceof DeleteEventsCmd || cmdObj instanceof ArchiveEventsCmd) {
boolean isObjInNewDateFormat = isObjInNewDateFormat(paramObj.toString()); boolean isObjInNewDateFormat = isObjInNewDateFormat(paramObj.toString());
if (isObjInNewDateFormat) { if (isObjInNewDateFormat) {
DateFormat newFormat = BaseCmd.NEW_INPUT_FORMAT; DateFormat newFormat = BaseCmd.NEW_INPUT_FORMAT;
@ -406,6 +408,8 @@ public class ApiDispatcher {
date = messageDate(date, 0, 0, 0); date = messageDate(date, 0, 0, 0);
} else if (field.getName().equals("endDate")) { } else if (field.getName().equals("endDate")) {
date = messageDate(date, 23, 59, 59); date = messageDate(date, 23, 59, 59);
} else if (field.getName().equals("olderThan")) {
date = messageDate(date, 0, 0, 0);
} }
field.set(cmdObj, date); field.set(cmdObj, date);
} }

View File

@ -397,6 +397,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
sb.and("state", sb.entity().getState(), SearchCriteria.Op.NEQ); sb.and("state", sb.entity().getState(), SearchCriteria.Op.NEQ);
sb.and("startId", sb.entity().getStartId(), SearchCriteria.Op.EQ); sb.and("startId", sb.entity().getStartId(), SearchCriteria.Op.EQ);
sb.and("createDate", sb.entity().getCreateDate(), SearchCriteria.Op.BETWEEN); sb.and("createDate", sb.entity().getCreateDate(), SearchCriteria.Op.BETWEEN);
sb.and("archived", sb.entity().getArchived(), SearchCriteria.Op.EQ);
SearchCriteria<EventJoinVO> sc = sb.create(); SearchCriteria<EventJoinVO> sc = sb.create();
// building ACL condition // building ACL condition
@ -430,6 +431,8 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
sc.setParameters("createDateL", endDate); sc.setParameters("createDateL", endDate);
} }
sc.setParameters("archived", false);
Pair<List<EventJoinVO>, Integer> eventPair = null; Pair<List<EventJoinVO>, Integer> eventPair = null;
// event_view will not have duplicate rows for each event, so searchAndCount should be good enough. // event_view will not have duplicate rows for each event, so searchAndCount should be good enough.
if ((entryTime != null) && (duration != null)) { if ((entryTime != null) && (duration != null)) {

View File

@ -104,6 +104,8 @@ public class EventJoinVO extends BaseViewVO implements ControlledViewEntity {
@Column(name="project_name") @Column(name="project_name")
private String projectName; private String projectName;
@Column(name="archived")
private boolean archived;
public EventJoinVO() { public EventJoinVO() {
@ -313,5 +315,12 @@ public class EventJoinVO extends BaseViewVO implements ControlledViewEntity {
this.parameters = parameters; this.parameters = parameters;
} }
public boolean getArchived() {
return archived;
}
public void setArchived(Boolean archived) {
this.archived = archived;
}
} }

View File

@ -204,9 +204,10 @@ public enum Config {
SecStorageSessionMax("Advanced", AgentManager.class, Integer.class, "secstorage.session.max", "50", "The max number of command execution sessions that a SSVM can handle", null), SecStorageSessionMax("Advanced", AgentManager.class, Integer.class, "secstorage.session.max", "50", "The max number of command execution sessions that a SSVM can handle", null),
SecStorageCmdExecutionTimeMax("Advanced", AgentManager.class, Integer.class, "secstorage.cmd.execution.time.max", "30", "The max command execution time in minute", null), SecStorageCmdExecutionTimeMax("Advanced", AgentManager.class, Integer.class, "secstorage.cmd.execution.time.max", "30", "The max command execution time in minute", null),
SecStorageProxy("Advanced", AgentManager.class, String.class, "secstorage.proxy", null, "http proxy used by ssvm, in http://username:password@proxyserver:port format", null), SecStorageProxy("Advanced", AgentManager.class, String.class, "secstorage.proxy", null, "http proxy used by ssvm, in http://username:password@proxyserver:port format", null),
AlertPurgeInterval("Advanced", ManagementServer.class, Integer.class, "alert.purge.interval", "86400", "The interval (in seconds) to wait before running the alert purge thread", null),
AlertPurgeDelay("Advanced", ManagementServer.class, Integer.class, "alert.purge.delay", "0", "Alerts older than specified number days will be purged. Set this value to 0 to never delete alerts", null),
DirectAttachNetworkEnabled("Advanced", ManagementServer.class, Boolean.class, "direct.attach.network.externalIpAllocator.enabled", "false", "Direct-attach VMs using external DHCP server", "true,false"),
DirectAttachNetworkEnabled("Advanced", ManagementServer.class, Boolean.class, "direct.attach.network.externalIpAllocator.enabled", "false", "Direct-attach VMs using external DHCP server", "true,false"),
DirectAttachNetworkExternalAPIURL("Advanced", ManagementServer.class, String.class, "direct.attach.network.externalIpAllocator.url", null, "Direct-attach VMs using external DHCP server (API url)", null), DirectAttachNetworkExternalAPIURL("Advanced", ManagementServer.class, String.class, "direct.attach.network.externalIpAllocator.url", null, "Direct-attach VMs using external DHCP server (API url)", null),
CheckPodCIDRs("Advanced", ManagementServer.class, String.class, "check.pod.cidrs", "true", "If true, different pods must belong to different CIDR subnets.", "true,false"), CheckPodCIDRs("Advanced", ManagementServer.class, String.class, "check.pod.cidrs", "true", "If true, different pods must belong to different CIDR subnets.", "true,false"),
NetworkGcWait("Advanced", ManagementServer.class, Integer.class, "network.gc.wait", "600", "Time (in seconds) to wait before shutting down a network that's not in used", null), NetworkGcWait("Advanced", ManagementServer.class, Integer.class, "network.gc.wait", "600", "Time (in seconds) to wait before shutting down a network that's not in used", null),

View File

@ -47,6 +47,7 @@ import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException; import javax.management.NotCompliantMBeanException;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
@ -125,6 +126,7 @@ import com.cloud.alert.AlertManager;
import com.cloud.alert.AlertVO; import com.cloud.alert.AlertVO;
import com.cloud.alert.dao.AlertDao; import com.cloud.alert.dao.AlertDao;
import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiDBUtils;
import com.cloud.api.query.vo.EventJoinVO;
import com.cloud.async.AsyncJobExecutor; import com.cloud.async.AsyncJobExecutor;
import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobManager;
import com.cloud.async.AsyncJobResult; import com.cloud.async.AsyncJobResult;
@ -188,6 +190,7 @@ import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
import com.cloud.info.ConsoleProxyInfo; import com.cloud.info.ConsoleProxyInfo;
import com.cloud.keystore.KeystoreManager; import com.cloud.keystore.KeystoreManager;
import com.cloud.network.IpAddress; import com.cloud.network.IpAddress;
import com.cloud.network.as.ConditionVO;
import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.LoadBalancerDao;
@ -262,6 +265,7 @@ import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction; import com.cloud.utils.db.Transaction;
@ -295,7 +299,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName()); public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName());
@Inject @Inject
private AccountManager _accountMgr; public AccountManager _accountMgr;
@Inject @Inject
private AgentManager _agentMgr; private AgentManager _agentMgr;
@Inject @Inject
@ -311,7 +315,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Inject @Inject
private SecondaryStorageVmDao _secStorageVmDao; private SecondaryStorageVmDao _secStorageVmDao;
@Inject @Inject
private EventDao _eventDao; public EventDao _eventDao;
@Inject @Inject
private DataCenterDao _dcDao; private DataCenterDao _dcDao;
@Inject @Inject
@ -347,7 +351,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Inject @Inject
private AccountDao _accountDao; private AccountDao _accountDao;
@Inject @Inject
private AlertDao _alertDao; public AlertDao _alertDao;
@Inject @Inject
private CapacityDao _capacityDao; private CapacityDao _capacityDao;
@Inject @Inject
@ -371,6 +375,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Inject @Inject
private AsyncJobManager _asyncMgr; private AsyncJobManager _asyncMgr;
private int _purgeDelay; private int _purgeDelay;
private int _alertPurgeDelay;
@Inject @Inject
private InstanceGroupDao _vmGroupDao; private InstanceGroupDao _vmGroupDao;
@Inject @Inject
@ -417,6 +422,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
EventUtils _forceEventUtilsRef; EventUtils _forceEventUtilsRef;
*/ */
private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker")); private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
private final ScheduledExecutorService _alertExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AlertChecker"));
private KeystoreManager _ksMgr; private KeystoreManager _ksMgr;
private Map<String, String> _configs; private Map<String, String> _configs;
@ -446,6 +452,15 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
_eventExecutor.scheduleAtFixedRate(new EventPurgeTask(), cleanup, cleanup, TimeUnit.SECONDS); _eventExecutor.scheduleAtFixedRate(new EventPurgeTask(), cleanup, cleanup, TimeUnit.SECONDS);
} }
//Alerts purge configurations
int alertPurgeInterval = NumbersUtil.parseInt(_configDao.getValue(Config.AlertPurgeInterval.key()),
60 * 60 * 24); // 1 day.
_alertPurgeDelay = NumbersUtil.parseInt(_configDao.getValue(Config.AlertPurgeDelay.key()), 0);
if (_alertPurgeDelay != 0) {
_alertExecutor.scheduleAtFixedRate(new AlertPurgeTask(), alertPurgeInterval, alertPurgeInterval,
TimeUnit.SECONDS);
}
String[] availableIds = TimeZone.getAvailableIDs(); String[] availableIds = TimeZone.getAvailableIDs();
_availableIdsMap = new HashMap<String, Boolean>(availableIds.length); _availableIdsMap = new HashMap<String, Boolean>(availableIds.length);
for (String id : availableIds) { for (String id : availableIds) {
@ -538,6 +553,42 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
return _eventDao.search(sc, null); return _eventDao.search(sc, null);
} }
@Override
public boolean archiveEvents(ArchiveEventsCmd cmd) {
List<Long> ids = cmd.getIds();
boolean result =true;
List<EventVO> events = _eventDao.listToArchiveOrDeleteEvents(ids, cmd.getType(), cmd.getOlderThan(), cmd.getEntityOwnerId());
ControlledEntity[] sameOwnerEvents = events.toArray(new ControlledEntity[events.size()]);
_accountMgr.checkAccess(UserContext.current().getCaller(), null, true, sameOwnerEvents);
if (ids != null && events.size() < ids.size()) {
result = false;
return result;
}
_eventDao.archiveEvents(events);
return result;
}
@Override
public boolean deleteEvents(DeleteEventsCmd cmd) {
List<Long> ids = cmd.getIds();
boolean result =true;
List<EventVO> events = _eventDao.listToArchiveOrDeleteEvents(ids, cmd.getType(), cmd.getOlderThan(), cmd.getEntityOwnerId());
ControlledEntity[] sameOwnerEvents = events.toArray(new ControlledEntity[events.size()]);
_accountMgr.checkAccess(UserContext.current().getCaller(), null, true, sameOwnerEvents);
if (ids != null && events.size() < ids.size()) {
result = false;
return result;
}
for (EventVO event : events) {
_eventDao.remove(event.getId());
}
return result;
}
private Date massageDate(Date date, int hourOfDay, int minute, int second) { private Date massageDate(Date date, int hourOfDay, int minute, int second) {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
cal.setTime(date); cal.setTime(date);
@ -1663,10 +1714,25 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
sc.addAnd("type", SearchCriteria.Op.EQ, type); sc.addAnd("type", SearchCriteria.Op.EQ, type);
} }
sc.addAnd("archived", SearchCriteria.Op.EQ, false);
Pair<List<AlertVO>, Integer> result = _alertDao.searchAndCount(sc, searchFilter); Pair<List<AlertVO>, Integer> result = _alertDao.searchAndCount(sc, searchFilter);
return new Pair<List<? extends Alert>, Integer>(result.first(), result.second()); return new Pair<List<? extends Alert>, Integer>(result.first(), result.second());
} }
@Override
public boolean archiveAlerts(ArchiveAlertsCmd cmd) {
Long zoneId = _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), null);
boolean result = _alertDao.archiveAlert(cmd.getIds(), cmd.getType(), cmd.getOlderThan(), zoneId);
return result;
}
@Override
public boolean deleteAlerts(DeleteAlertsCmd cmd) {
Long zoneId = _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), null);
boolean result = _alertDao.deleteAlert(cmd.getIds(), cmd.getType(), cmd.getOlderThan(), zoneId);
return result;
}
@Override @Override
public List<CapacityVO> listTopConsumedResources(ListCapacityCmd cmd) { public List<CapacityVO> listTopConsumedResources(ListCapacityCmd cmd) {
@ -2168,6 +2234,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(AddIpToVmNicCmd.class); cmdList.add(AddIpToVmNicCmd.class);
cmdList.add(RemoveIpFromVmNicCmd.class); cmdList.add(RemoveIpFromVmNicCmd.class);
cmdList.add(ListNicsCmd.class); cmdList.add(ListNicsCmd.class);
cmdList.add(ArchiveAlertsCmd.class);
cmdList.add(DeleteAlertsCmd.class);
cmdList.add(ArchiveEventsCmd.class);
cmdList.add(DeleteEventsCmd.class);
return cmdList; return cmdList;
} }
@ -2205,6 +2275,39 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
} }
} }
protected class AlertPurgeTask implements Runnable {
@Override
public void run() {
try {
GlobalLock lock = GlobalLock.getInternLock("AlertPurge");
if (lock == null) {
s_logger.debug("Couldn't get the global lock");
return;
}
if (!lock.lock(30)) {
s_logger.debug("Couldn't lock the db");
return;
}
try {
final Calendar purgeCal = Calendar.getInstance();
purgeCal.add(Calendar.DAY_OF_YEAR, - _alertPurgeDelay);
Date purgeTime = purgeCal.getTime();
s_logger.debug("Deleting alerts older than: " + purgeTime.toString());
List<AlertVO> oldAlerts = _alertDao.listOlderAlerts(purgeTime);
s_logger.debug("Found " + oldAlerts.size() + " events to be purged");
for (AlertVO alert : oldAlerts) {
_alertDao.expunge(alert.getId());
}
} catch (Exception e) {
s_logger.error("Exception ", e);
} finally {
lock.unlock();
}
} catch (Exception e) {
s_logger.error("Exception ", e);
}
}
}
@Override @Override
public Pair<List<StoragePoolVO>, Integer> searchForStoragePools(Criteria c) { public Pair<List<StoragePoolVO>, Integer> searchForStoragePools(Criteria c) {

View File

@ -0,0 +1,67 @@
package com.cloud.alert;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
import java.util.Date;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import com.cloud.alert.dao.AlertDao;
import com.cloud.server.ManagementServerImpl;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
public class AlertControlsUnitTest extends TestCase {
private static final Logger s_logger = Logger.getLogger(AlertControlsUnitTest.class);
@Spy ManagementServerImpl _mgmtServer = new ManagementServerImpl();
@Mock AccountManager _accountMgr;
@Mock AlertDao _alertDao;
@Override
@Before
protected void setUp() {
MockitoAnnotations.initMocks(this);
_mgmtServer._alertDao = _alertDao;
_mgmtServer._accountMgr = _accountMgr;
doReturn(3L).when(_accountMgr).checkAccessAndSpecifyAuthority(any(Account.class), anyLong());
when(_alertDao.archiveAlert(anyList(), anyString(), any(Date.class), anyLong())).thenReturn(true);
when(_alertDao.deleteAlert(anyList(), anyString(), any(Date.class), anyLong())).thenReturn(true);
}
@After
public void tearDown() throws Exception {
}
@Test
public void testInjected() throws Exception {
s_logger.info("Starting test to archive and delete alerts");
archiveAlerts();
deleteAlerts();
s_logger.info("archive/delete alerts: TEST PASSED");
}
protected void archiveAlerts() {
// archive alerts
String msg = "Archive Alerts: TEST FAILED";
assertNotNull(msg, _mgmtServer._alertDao.archiveAlert(null, "system alert",null, 2L));
}
protected void deleteAlerts() {
// delete alerts
String msg = "Delete Alerts: TEST FAILED";
assertNotNull(msg, _mgmtServer._alertDao.deleteAlert(null, "system alert",null, 2L));
}
}

View File

@ -0,0 +1,68 @@
package com.cloud.event;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import java.util.Date;
import java.util.List;
import junit.framework.TestCase;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import com.cloud.event.dao.EventDao;
import com.cloud.server.ManagementServerImpl;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
public class EventControlsUnitTest extends TestCase{
private static final Logger s_logger = Logger.getLogger(EventControlsUnitTest.class);
@Spy ManagementServerImpl _mgmtServer = new ManagementServerImpl();
@Mock AccountManager _accountMgr;
@Mock EventDao _eventDao;
List<EventVO> _events = null;
@Override
@Before
protected void setUp() {
MockitoAnnotations.initMocks(this);
_mgmtServer._eventDao = _eventDao;
_mgmtServer._accountMgr = _accountMgr;
doNothing().when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
when(_eventDao.listToArchiveOrDeleteEvents(anyList(), anyString(), any(Date.class), anyLong())).thenReturn(_events);
}
@After
public void tearDown() throws Exception {
}
@Test
public void testInjected() throws Exception {
s_logger.info("Starting test to archive and delete events");
archiveEvents();
deleteEvents();
s_logger.info("archive/delete events: TEST PASSED");
}
protected void archiveEvents() {
// archive alerts
doNothing().when(_eventDao).archiveEvents(_events);
}
protected void deleteEvents() {
// delete alerts
}
}

View File

@ -140,3 +140,48 @@ CREATE TABLE nic_secondary_ips (
ALTER TABLE `cloud`.`nics` ADD COLUMN secondary_ip SMALLINT DEFAULT '0' COMMENT 'secondary ips configured for the nic'; ALTER TABLE `cloud`.`nics` ADD COLUMN secondary_ip SMALLINT DEFAULT '0' COMMENT 'secondary ips configured for the nic';
ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN dnat_vmip VARCHAR(40); ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN dnat_vmip VARCHAR(40);
ALTER TABLE `cloud`.`alert` ADD COLUMN `archived` tinyint(1) unsigned NOT NULL DEFAULT 0;
ALTER TABLE `cloud`.`event` ADD COLUMN `archived` tinyint(1) unsigned NOT NULL DEFAULT 0;
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'alert.purge.interval', '86400', 'The interval (in seconds) to wait before running the alert purge thread');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'alert.purge.delay', '0', 'Alerts older than specified number days will be purged. Set this value to 0 to never delete alerts');
DROP VIEW IF EXISTS `cloud`.`event_view`;
CREATE VIEW `cloud`.`event_view` AS
select
event.id,
event.uuid,
event.type,
event.state,
event.description,
event.created,
event.level,
event.parameters,
event.start_id,
eve.uuid start_uuid,
event.user_id,
event.archived,
user.username user_name,
account.id account_id,
account.uuid account_uuid,
account.account_name account_name,
account.type account_type,
domain.id domain_id,
domain.uuid domain_uuid,
domain.name domain_name,
domain.path domain_path,
projects.id project_id,
projects.uuid project_uuid,
projects.name project_name
from
`cloud`.`event`
inner join
`cloud`.`account` ON event.account_id = account.id
inner join
`cloud`.`domain` ON event.domain_id = domain.id
inner join
`cloud`.`user` ON event.user_id = user.id
left join
`cloud`.`projects` ON projects.project_account_id = event.account_id
left join
`cloud`.`event` eve ON event.start_id = eve.id;