diff --git a/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java index 79c34d0690f..d2b696d2b6b 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java @@ -33,7 +33,7 @@ import com.cloud.user.Account; @APICommand(name = "removeRegion", description="Removes specified region", responseObject=SuccessResponse.class) public class RemoveRegionCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(RemoveRegionCmd.class.getName()); - private static final String s_name = "updateregionresponse"; + private static final String s_name = "removeregionresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// diff --git a/client/pom.xml b/client/pom.xml index cda6ab8b4e7..ecf232be7ac 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -65,6 +65,11 @@ cloud-plugin-network-nvp ${project.version} + + org.apache.cloudstack + cloud-plugin-snmp-alerts + ${project.version} + org.apache.cloudstack cloud-plugin-network-ovs diff --git a/client/tomcatconf/log4j-cloud.xml.in b/client/tomcatconf/log4j-cloud.xml.in index 086669376aa..ce4079f9c96 100755 --- a/client/tomcatconf/log4j-cloud.xml.in +++ b/client/tomcatconf/log4j-cloud.xml.in @@ -74,6 +74,20 @@ under the License. + + + + + + + + + + + + + + @@ -142,6 +156,17 @@ under the License. + + + + + + + + + + + diff --git a/core/src/com/cloud/alert/AlertManager.java b/core/src/com/cloud/alert/AlertManager.java index a24e18c8373..b6d005a5f21 100755 --- a/core/src/com/cloud/alert/AlertManager.java +++ b/core/src/com/cloud/alert/AlertManager.java @@ -27,26 +27,27 @@ public interface AlertManager extends Manager { public static final short ALERT_TYPE_VIRTUAL_NETWORK_PUBLIC_IP = CapacityVO.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP; public static final short ALERT_TYPE_PRIVATE_IP = CapacityVO.CAPACITY_TYPE_PRIVATE_IP; public static final short ALERT_TYPE_SECONDARY_STORAGE = CapacityVO.CAPACITY_TYPE_SECONDARY_STORAGE; - public static final short ALERT_TYPE_HOST = 6; - public static final short ALERT_TYPE_USERVM = 7; - public static final short ALERT_TYPE_DOMAIN_ROUTER = 8; - public static final short ALERT_TYPE_CONSOLE_PROXY = 9; - public static final short ALERT_TYPE_ROUTING = 10; // lost connection to default route (to the gateway) - public static final short ALERT_TYPE_STORAGE_MISC = 11; // lost connection to default route (to the gateway) - public static final short ALERT_TYPE_USAGE_SERVER = 12; // lost connection to default route (to the gateway) - public static final short ALERT_TYPE_MANAGMENT_NODE = 13; // lost connection to default route (to the gateway) - public static final short ALERT_TYPE_DOMAIN_ROUTER_MIGRATE = 14; - public static final short ALERT_TYPE_CONSOLE_PROXY_MIGRATE = 15; - public static final short ALERT_TYPE_USERVM_MIGRATE = 16; - public static final short ALERT_TYPE_VLAN = 17; - public static final short ALERT_TYPE_SSVM = 18; - public static final short ALERT_TYPE_USAGE_SERVER_RESULT = 19; // Usage job result - public static final short ALERT_TYPE_STORAGE_DELETE = 20; - public static final short ALERT_TYPE_UPDATE_RESOURCE_COUNT = 21; // Generated when we fail to update the resource count - public static final short ALERT_TYPE_USAGE_SANITY_RESULT = 22; - public static final short ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 23; - public static final short ALERT_TYPE_LOCAL_STORAGE = 24; - public static final short ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = 25; // Generated when the resource limit exceeds the limit. Currently used for recurring snapshots only + public static final short ALERT_TYPE_HOST = 7; + public static final short ALERT_TYPE_USERVM = 8; + public static final short ALERT_TYPE_DOMAIN_ROUTER = 9; + public static final short ALERT_TYPE_CONSOLE_PROXY = 10; + public static final short ALERT_TYPE_ROUTING = 11; // lost connection to default route (to the gateway) + public static final short ALERT_TYPE_STORAGE_MISC = 12; // lost connection to default route (to the gateway) + public static final short ALERT_TYPE_USAGE_SERVER = 13; // lost connection to default route (to the gateway) + public static final short ALERT_TYPE_MANAGMENT_NODE = 14; // lost connection to default route (to the gateway) + public static final short ALERT_TYPE_DOMAIN_ROUTER_MIGRATE = 15; + public static final short ALERT_TYPE_CONSOLE_PROXY_MIGRATE = 16; + public static final short ALERT_TYPE_USERVM_MIGRATE = 17; + public static final short ALERT_TYPE_VLAN = 18; + public static final short ALERT_TYPE_SSVM = 19; + public static final short ALERT_TYPE_USAGE_SERVER_RESULT = 20; // Usage job result + public static final short ALERT_TYPE_STORAGE_DELETE = 21; + public static final short ALERT_TYPE_UPDATE_RESOURCE_COUNT = 22; // Generated when we fail to update the resource + // count + public static final short ALERT_TYPE_USAGE_SANITY_RESULT = 23; + public static final short ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 24; + public static final short ALERT_TYPE_LOCAL_STORAGE = 25; + public static final short ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = 26; // Generated when the resource limit exceeds the limit. Currently used for recurring snapshots only void clearAlert(short alertType, long dataCenterId, long podId); diff --git a/plugins/alert-handlers/snmp-alerts/pom.xml b/plugins/alert-handlers/snmp-alerts/pom.xml new file mode 100644 index 00000000000..b5cebf31b7a --- /dev/null +++ b/plugins/alert-handlers/snmp-alerts/pom.xml @@ -0,0 +1,45 @@ + + + + cloudstack-plugins + org.apache.cloudstack + 4.2.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + Apache CloudStack Plugin - SNMP Alerts + cloud-plugin-snmp-alerts + + + + org.apache.servicemix.bundles + org.apache.servicemix.bundles.snmp4j + 2.1.0_1 + + + log4j + log4j + ${cs.log4j.version} + + + + diff --git a/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/CsSnmpConstants.java b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/CsSnmpConstants.java new file mode 100644 index 00000000000..36970a958fd --- /dev/null +++ b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/CsSnmpConstants.java @@ -0,0 +1,45 @@ +// 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.alert.snmp; + +/** + *

+ * IMPORTANT + *

+ * These OIDs are based on CS-ROOT-MIB MIB file. If there is any change in MIB file + * then that should be reflected in this file also * + *

+ * suffix 2 due to conflict with SnmpConstants class of snmp4j + */ +public class CsSnmpConstants { + public static final String CLOUDSTACK = "1.3.6.1.4.1.18060.15"; + + public static final String OBJECTS_PREFIX = CLOUDSTACK + ".1.1."; + + public static final String TRAPS_PREFIX = CLOUDSTACK + ".1.2.0."; + + public static final String DATA_CENTER_ID = OBJECTS_PREFIX + 1; + + public static final String POD_ID = OBJECTS_PREFIX + 2; + + public static final String CLUSTER_ID = OBJECTS_PREFIX + 3; + + public static final String MESSAGE = OBJECTS_PREFIX + 4; + + public static final String GENERATION_TIME = OBJECTS_PREFIX + 5; +} \ No newline at end of file diff --git a/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpEnhancedPatternLayout.java b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpEnhancedPatternLayout.java new file mode 100644 index 00000000000..67420915607 --- /dev/null +++ b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpEnhancedPatternLayout.java @@ -0,0 +1,107 @@ +// 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.alert.snmp; + +import org.apache.log4j.EnhancedPatternLayout; +import org.apache.log4j.spi.LoggingEvent; + +import java.util.Date; +import java.util.StringTokenizer; + +public class SnmpEnhancedPatternLayout extends EnhancedPatternLayout { + private String _pairDelimiter = "//"; + private String _keyValueDelimiter = "::"; + + private static final int LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER = 9; + private static final int LENGTH_OF_STRING_MESSAGE = 8; + + public String getKeyValueDelimeter() { + return _keyValueDelimiter; + } + + public void setKeyValueDelimiter(String keyValueDelimiter) { + this._keyValueDelimiter = keyValueDelimiter; + } + + public String getPairDelimiter() { + return _pairDelimiter; + } + + public void setPairDelimiter(String pairDelimiter) { + this._pairDelimiter = pairDelimiter; + } + + public SnmpTrapInfo parseEvent(LoggingEvent event) { + SnmpTrapInfo snmpTrapInfo = null; + + final String message = event.getRenderedMessage(); + if (message.contains("alertType") && message.contains("message")) { + snmpTrapInfo = new SnmpTrapInfo(); + final StringTokenizer messageSplitter = new StringTokenizer(message, _pairDelimiter); + while (messageSplitter.hasMoreTokens()) { + final String pairToken = messageSplitter.nextToken(); + final StringTokenizer pairSplitter = new StringTokenizer(pairToken, _keyValueDelimiter); + String keyToken; + String valueToken; + + if (pairSplitter.hasMoreTokens()) { + keyToken = pairSplitter.nextToken().trim(); + } else { + break; + } + + if (pairSplitter.hasMoreTokens()) { + valueToken = pairSplitter.nextToken().trim(); + } else { + break; + } + + if (keyToken.equalsIgnoreCase("alertType") && !valueToken.equalsIgnoreCase("null")) { + snmpTrapInfo.setAlertType(Short.parseShort(valueToken)); + } else if (keyToken.equalsIgnoreCase("dataCenterId") && !valueToken.equalsIgnoreCase("null")) { + snmpTrapInfo.setDataCenterId(Long.parseLong(valueToken)); + } else if (keyToken.equalsIgnoreCase("podId") && !valueToken.equalsIgnoreCase("null")) { + snmpTrapInfo.setPodId(Long.parseLong(valueToken)); + } else if (keyToken.equalsIgnoreCase("clusterId") && !valueToken.equalsIgnoreCase("null")) { + snmpTrapInfo.setClusterId(Long.parseLong(valueToken)); + } else if (keyToken.equalsIgnoreCase("message") && !valueToken.equalsIgnoreCase("null")) { + snmpTrapInfo.setMessage(getSnmpMessage(message)); + } + } + + snmpTrapInfo.setGenerationTime(new Date(event.getTimeStamp())); + } + return snmpTrapInfo; + } + + private String getSnmpMessage(String message) { + int lastIndexOfKeyValueDelimiter = message.lastIndexOf(_keyValueDelimiter); + int lastIndexOfMessageInString = message.lastIndexOf("message"); + + if (lastIndexOfKeyValueDelimiter - lastIndexOfMessageInString <= + LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER) { + return message.substring(lastIndexOfKeyValueDelimiter + _keyValueDelimiter.length()).trim(); + } else if (lastIndexOfMessageInString < lastIndexOfKeyValueDelimiter) { + return message.substring( + lastIndexOfMessageInString + _keyValueDelimiter.length() + LENGTH_OF_STRING_MESSAGE).trim(); + } + + return message.substring(message.lastIndexOf("message" + _keyValueDelimiter) + + LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER).trim(); + } +} \ No newline at end of file diff --git a/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpHelper.java b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpHelper.java new file mode 100644 index 00000000000..4bee94bd9d0 --- /dev/null +++ b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpHelper.java @@ -0,0 +1,106 @@ +// 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.alert.snmp; + +import com.cloud.utils.exception.CloudRuntimeException; +import org.snmp4j.CommunityTarget; +import org.snmp4j.PDU; +import org.snmp4j.Snmp; +import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.OctetString; +import org.snmp4j.smi.UdpAddress; +import org.snmp4j.smi.UnsignedInteger32; +import org.snmp4j.smi.VariableBinding; +import org.snmp4j.transport.DefaultUdpTransportMapping; + +import java.io.IOException; + +public class SnmpHelper { + private Snmp _snmp; + private CommunityTarget _target; + + public SnmpHelper(String address, String community) { + _target = new CommunityTarget(); + _target.setCommunity(new OctetString(community)); + _target.setVersion(SnmpConstants.version2c); + _target.setAddress(new UdpAddress(address)); + try { + _snmp = new Snmp(new DefaultUdpTransportMapping()); + } catch (IOException e) { + _snmp = null; + throw new CloudRuntimeException(" Error in crearting snmp object, " + e.getMessage()); + } + } + + public void sendSnmpTrap(SnmpTrapInfo snmpTrapInfo) { + try { + if (_snmp != null) { + _snmp.send(createPDU(snmpTrapInfo), _target, null, null); + } + } catch (IOException e) { + throw new CloudRuntimeException(" Error in sending SNMP Trap, " + e.getMessage()); + } + } + + private PDU createPDU(SnmpTrapInfo snmpTrapInfo) { + PDU trap = new PDU(); + trap.setType(PDU.TRAP); + + int alertType = snmpTrapInfo.getAlertType() + 1; + if (alertType > 0) { + trap.add(new VariableBinding(SnmpConstants.snmpTrapOID, getOID(CsSnmpConstants.TRAPS_PREFIX + alertType))); + if (snmpTrapInfo.getDataCenterId() != 0) { + trap.add(new VariableBinding(getOID(CsSnmpConstants.DATA_CENTER_ID), + new UnsignedInteger32(snmpTrapInfo.getDataCenterId()))); + } + + if (snmpTrapInfo.getPodId() != 0) { + trap.add(new VariableBinding(getOID(CsSnmpConstants.POD_ID), new UnsignedInteger32(snmpTrapInfo + .getPodId()))); + } + + if (snmpTrapInfo.getClusterId() != 0) { + trap.add(new VariableBinding(getOID(CsSnmpConstants.CLUSTER_ID), new UnsignedInteger32(snmpTrapInfo + .getClusterId()))); + } + + if (snmpTrapInfo.getMessage() != null) { + trap.add(new VariableBinding(getOID(CsSnmpConstants.MESSAGE), new OctetString(snmpTrapInfo.getMessage + ()))); + } else { + throw new CloudRuntimeException(" What is the use of alert without message "); + } + + if (snmpTrapInfo.getGenerationTime() != null) { + trap.add(new VariableBinding(getOID(CsSnmpConstants.GENERATION_TIME), + new OctetString(snmpTrapInfo.getGenerationTime().toString()))); + } else { + trap.add(new VariableBinding(getOID(CsSnmpConstants.GENERATION_TIME))); + } + } else { + throw new CloudRuntimeException(" Invalid alert Type "); + } + + return trap; + } + + private OID getOID(String oidString) { + return new OID(oidString); + } +} \ No newline at end of file diff --git a/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpTrapAppender.java b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpTrapAppender.java new file mode 100644 index 00000000000..eaa4a132b7e --- /dev/null +++ b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpTrapAppender.java @@ -0,0 +1,207 @@ +// 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.alert.snmp; + +import com.cloud.utils.net.NetUtils; +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.spi.ErrorCode; +import org.apache.log4j.spi.LoggingEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +public class SnmpTrapAppender extends AppenderSkeleton { + private String _delimiter = ","; + private String _snmpManagerIpAddresses; + private String _snmpManagerPorts; + private String _snmpManagerCommunities; + + private String _oldSnmpManagerIpAddresses = null; + private String _oldSnmpManagerPorts = null; + private String _oldSnmpManagerCommunities = null; + + private List _ipAddresses = null; + private List _communities = null; + private List _ports = null; + + List _snmpHelpers = new ArrayList(); + + @Override + protected void append(LoggingEvent event) { + SnmpEnhancedPatternLayout snmpEnhancedPatternLayout; + + if (getLayout() == null) { + errorHandler.error("No layout set for the Appender named [" + getName() + ']', null, + ErrorCode.MISSING_LAYOUT); + return; + } + + if (getLayout() instanceof SnmpEnhancedPatternLayout) { + snmpEnhancedPatternLayout = (SnmpEnhancedPatternLayout) getLayout(); + } else { + return; + } + + if (!isAsSevereAsThreshold(event.getLevel())) { + return; + } + + SnmpTrapInfo snmpTrapInfo = snmpEnhancedPatternLayout.parseEvent(event); + + if (snmpTrapInfo != null && !_snmpHelpers.isEmpty()) { + for (SnmpHelper helper : _snmpHelpers) { + try { + helper.sendSnmpTrap(snmpTrapInfo); + } catch (Exception e) { + errorHandler.error(e.getMessage()); + } + } + } + } + + void setSnmpHelpers() { + if (_snmpManagerIpAddresses == null || _snmpManagerIpAddresses.trim().isEmpty() || _snmpManagerCommunities == + null || _snmpManagerCommunities.trim().isEmpty() || _snmpManagerPorts == null || + _snmpManagerPorts.trim().isEmpty()) { + reset(); + return; + } + + if (_oldSnmpManagerIpAddresses != null && _oldSnmpManagerIpAddresses.equals(_snmpManagerIpAddresses) && + _oldSnmpManagerCommunities.equals(_snmpManagerCommunities) && + _oldSnmpManagerPorts.equals(_snmpManagerPorts)) { + return; + } + + _oldSnmpManagerIpAddresses = _snmpManagerIpAddresses; + _oldSnmpManagerPorts = _snmpManagerPorts; + _oldSnmpManagerCommunities = _snmpManagerCommunities; + + _ipAddresses = parse(_snmpManagerIpAddresses); + _communities = parse(_snmpManagerCommunities); + _ports = parse(_snmpManagerPorts); + + if (!(_ipAddresses.size() == _communities.size() && _ipAddresses.size() == _ports.size())) { + reset(); + errorHandler.error(" size of ip addresses , communities, " + "and ports list doesn't match, " + + "setting all to null"); + return; + } + + if (!validateIpAddresses() || !validatePorts()) { + reset(); + errorHandler.error(" Invalid format for the IP Addresses or Ports parameter "); + return; + } + + String address; + + for (int i = 0; i < _ipAddresses.size(); i++) { + address = _ipAddresses.get(i) + "/" + _ports.get(i); + try { + _snmpHelpers.add(new SnmpHelper(address, _communities.get(i))); + } catch (Exception e) { + errorHandler.error(e.getMessage()); + } + } + } + + private void reset() { + _ipAddresses = null; + _communities = null; + _ports = null; + _snmpHelpers.clear(); + } + + @Override + public void close() { + if (!closed) closed = true; + } + + @Override + public boolean requiresLayout() { + return true; + } + + private List parse(String str) { + List result = new ArrayList(); + + final StringTokenizer tokenizer = new StringTokenizer(str, _delimiter); + while (tokenizer.hasMoreTokens()) { + result.add(tokenizer.nextToken().trim()); + } + return result; + } + + private boolean validatePorts() { + for (String port : _ports) { + if (!NetUtils.isValidPort(port)) { + return false; + } + } + return true; + } + + private boolean validateIpAddresses() { + for (String ipAddress : _ipAddresses) { + if (ipAddress.trim().equalsIgnoreCase("localhost")) { + continue; + } + if (!NetUtils.isValidIp(ipAddress)) { + return false; + } + } + return true; + } + + public String getSnmpManagerIpAddresses() { + return _snmpManagerIpAddresses; + } + + public void setSnmpManagerIpAddresses(String snmpManagerIpAddresses) { + this._snmpManagerIpAddresses = snmpManagerIpAddresses; + setSnmpHelpers(); + } + + public String getSnmpManagerPorts() { + return _snmpManagerPorts; + } + + public void setSnmpManagerPorts(String snmpManagerPorts) { + this._snmpManagerPorts = snmpManagerPorts; + setSnmpHelpers(); + } + + public String getSnmpManagerCommunities() { + return _snmpManagerCommunities; + } + + public void setSnmpManagerCommunities(String snmpManagerCommunities) { + this._snmpManagerCommunities = snmpManagerCommunities; + setSnmpHelpers(); + } + + public String getDelimiter() { + return _delimiter; + } + + public void setDelimiter(String delimiter) { + this._delimiter = delimiter; + } +} \ No newline at end of file diff --git a/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpTrapInfo.java b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpTrapInfo.java new file mode 100644 index 00000000000..71bfee02cb6 --- /dev/null +++ b/plugins/alert-handlers/snmp-alerts/src/org/apache/cloudstack/alert/snmp/SnmpTrapInfo.java @@ -0,0 +1,90 @@ +// 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.alert.snmp; + +import java.util.Date; + +public class SnmpTrapInfo { + private String message; + private long podId; + private long dataCenterId; + private long clusterId; + private Date generationTime; + private short alertType; + + public SnmpTrapInfo() { + } + + public SnmpTrapInfo(short alertType, long dataCenterId, long podId, long clusterId, String message, + Date generationTime) { + this.podId = podId; + this.alertType = alertType; + this.clusterId = clusterId; + this.dataCenterId = dataCenterId; + this.generationTime = generationTime; + this.message = message; + } + + public short getAlertType() { + return alertType; + } + + public void setAlertType(short alertType) { + this.alertType = alertType; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public long getPodId() { + return podId; + } + + public void setPodId(long podId) { + this.podId = podId; + } + + public long getDataCenterId() { + return dataCenterId; + } + + public void setDataCenterId(long dataCenterId) { + this.dataCenterId = dataCenterId; + } + + public long getClusterId() { + return clusterId; + } + + public void setClusterId(long clusterId) { + this.clusterId = clusterId; + } + + public Date getGenerationTime() { + return generationTime; + } + + public void setGenerationTime(Date generationTime) { + this.generationTime = generationTime; + } +} \ No newline at end of file diff --git a/plugins/alert-handlers/snmp-alerts/test/org/apache/cloudstack/alert/snmp/SnmpEnhancedPatternLayoutTest.java b/plugins/alert-handlers/snmp-alerts/test/org/apache/cloudstack/alert/snmp/SnmpEnhancedPatternLayoutTest.java new file mode 100644 index 00000000000..b903a1e18b9 --- /dev/null +++ b/plugins/alert-handlers/snmp-alerts/test/org/apache/cloudstack/alert/snmp/SnmpEnhancedPatternLayoutTest.java @@ -0,0 +1,90 @@ +// 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.alert.snmp; + +import org.apache.log4j.spi.LoggingEvent; +import org.junit.Before; +import org.junit.Test; + +import javax.naming.ConfigurationException; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SnmpEnhancedPatternLayoutTest { + SnmpEnhancedPatternLayout _snmpEnhancedPatternLayout = new SnmpEnhancedPatternLayout(); + + @Before + public void setUp() throws ConfigurationException { + _snmpEnhancedPatternLayout.setKeyValueDelimiter("::"); + _snmpEnhancedPatternLayout.setPairDelimiter("//"); + } + + @Test + public void parseAlertTest() { + LoggingEvent event = mock(LoggingEvent.class); + setMessage(" alertType:: 14 // dataCenterId:: 1 // podId:: 1 // " + "clusterId:: null // message:: Management" + + " network CIDR is not configured originally. Set it default to 10.102.192.0/22", event); + SnmpTrapInfo info = _snmpEnhancedPatternLayout.parseEvent(event); + commonAssertions(info, "Management network CIDR is not configured originally. Set it default to 10.102.192" + + ".0/22"); + } + + @Test + public void ParseAlertWithPairDelimeterInMessageTest() { + LoggingEvent event = mock(LoggingEvent.class); + setMessage(" alertType:: 14 // dataCenterId:: 1 // podId:: 1 // " + "clusterId:: null // message:: Management" + + " //network CIDR is not configured originally. Set it default to 10.102.192.0/22", event); + SnmpTrapInfo info = _snmpEnhancedPatternLayout.parseEvent(event); + commonAssertions(info, "Management //network CIDR is not configured originally. Set it default to 10.102.192" + + ".0/22"); + } + + @Test + public void ParseAlertWithKeyValueDelimeterInMessageTest() { + LoggingEvent event = mock(LoggingEvent.class); + setMessage(" alertType:: 14 // dataCenterId:: 1 // podId:: 1 // " + "clusterId:: null // message:: Management" + + " ::network CIDR is not configured originally. Set it default to 10.102.192.0/22", event); + SnmpTrapInfo info = _snmpEnhancedPatternLayout.parseEvent(event); + commonAssertions(info, "Management ::network CIDR is not configured originally. Set it default to 10.102.192" + + ".0/22"); + } + + @Test + public void parseRandomTest() { + LoggingEvent event = mock(LoggingEvent.class); + when(event.getRenderedMessage()).thenReturn("Problem clearing email alert"); + assertNull(" Null value was expected ", _snmpEnhancedPatternLayout.parseEvent(event)); + } + + private void commonAssertions(SnmpTrapInfo info, String message) { + assertEquals(" alert type not as expected ", 14, info.getAlertType()); + assertEquals(" data center id not as expected ", 1, info.getDataCenterId()); + assertEquals(" pod id os not as expected ", 1, info.getPodId()); + assertEquals(" cluster id is not as expected ", 0, info.getClusterId()); + assertNotNull(" generation time is set to null", info.getGenerationTime()); + assertEquals(" message is not as expected ", message, info.getMessage()); + } + + private void setMessage(String message, LoggingEvent event) { + when(event.getRenderedMessage()).thenReturn(message); + } +} \ No newline at end of file diff --git a/plugins/alert-handlers/snmp-alerts/test/org/apache/cloudstack/alert/snmp/SnmpTrapAppenderTest.java b/plugins/alert-handlers/snmp-alerts/test/org/apache/cloudstack/alert/snmp/SnmpTrapAppenderTest.java new file mode 100644 index 00000000000..2a65d90acc2 --- /dev/null +++ b/plugins/alert-handlers/snmp-alerts/test/org/apache/cloudstack/alert/snmp/SnmpTrapAppenderTest.java @@ -0,0 +1,86 @@ +// 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.alert.snmp; + +import org.apache.log4j.spi.LoggingEvent; +import org.junit.Test; +import org.mockito.Mock; + +import java.util.List; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +public class SnmpTrapAppenderTest { + SnmpTrapAppender _appender = new SnmpTrapAppender(); + LoggingEvent _event = mock(LoggingEvent.class); + SnmpEnhancedPatternLayout _snmpEnhancedPatternLayout = mock(SnmpEnhancedPatternLayout.class); + @Mock + List snmpHelpers; + + @Test + public void appendTest() { + _appender.setSnmpManagerIpAddresses("10.1.1.1,10.1.1.2"); + _appender.setSnmpManagerPorts("162,164"); + _appender.setSnmpManagerCommunities("public,snmp"); + + _appender.setSnmpHelpers(); + assertEquals(" error snmpHelper list size not as expected ", _appender._snmpHelpers.size(), 2); + } + + @Test + public void InvalidInputTest() { + _appender.setSnmpManagerIpAddresses("10.1.1.1,10.1.1.2"); + _appender.setSnmpManagerPorts("162,164"); + _appender.setSnmpManagerCommunities("public"); + + _appender.setSnmpHelpers(); + assertTrue(" list was expected to be empty", _appender._snmpHelpers.isEmpty()); + } + + @Test + public void InvalidIpInputTest() { + _appender.setSnmpManagerIpAddresses("10.1.1,10.1.1.2"); + _appender.setSnmpManagerPorts("162,164"); + _appender.setSnmpManagerCommunities("public,snmp"); + + _appender.setSnmpHelpers(); + assertTrue(" list was expected to be empty", _appender._snmpHelpers.isEmpty()); + } + + @Test + public void InvalidPortInputTest() { + _appender.setSnmpManagerIpAddresses("10.1.1,10.1.1.2"); + _appender.setSnmpManagerPorts("162,164897489978"); + _appender.setSnmpManagerCommunities("public,snmp"); + + _appender.setSnmpHelpers(); + assertTrue(" list was expected to be empty", _appender._snmpHelpers.isEmpty()); + } + + @Test + public void mismatchListLengthInputTest() { + _appender.setSnmpManagerIpAddresses("10.1.1"); + _appender.setSnmpManagerPorts("162,164"); + _appender.setSnmpManagerCommunities("public,snmp"); + + _appender.setSnmpHelpers(); + assertTrue(" list was expected to be empty", _appender._snmpHelpers.isEmpty()); + } +} \ No newline at end of file diff --git a/plugins/pom.xml b/plugins/pom.xml index 88f617b4560..5d31a72ee91 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -57,6 +57,7 @@ network-elements/dns-notifier storage/image/s3 storage/volume/solidfire + alert-handlers/snmp-alerts diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index f8a8fd8b1b9..a45482fd4ef 100755 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -84,6 +84,7 @@ import com.sun.mail.smtp.SMTPTransport; @Local(value={AlertManager.class}) public class AlertManagerImpl extends ManagerBase implements AlertManager { private static final Logger s_logger = Logger.getLogger(AlertManagerImpl.class.getName()); + private static final Logger s_alertsLogger = Logger.getLogger("org.apache.cloudstack.alerts"); private static final long INITIAL_CAPACITY_CHECK_DELAY = 30L * 1000L; // thirty seconds expressed in milliseconds @@ -256,6 +257,9 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager { try { if (_emailAlert != null) { _emailAlert.sendAlert(alertType, dataCenterId, podId, null, subject, body); + } else { + s_alertsLogger.warn(" alertType:: " + alertType + " // dataCenterId:: " + dataCenterId + " // podId:: " + + podId + " // clusterId:: " + null + " // message:: " + subject ); } } catch (Exception ex) { s_logger.error("Problem sending email alert", ex); @@ -789,6 +793,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager { // TODO: make sure this handles SSL transport (useAuth is true) and regular public void sendAlert(short alertType, long dataCenterId, Long podId, Long clusterId, String subject, String content) throws MessagingException, UnsupportedEncodingException { + s_alertsLogger.warn(" alertType:: " + alertType + " // dataCenterId:: " + dataCenterId + " // podId:: " + + podId + " // clusterId:: " + null + " // message:: " + subject); AlertVO alert = null; if ((alertType != AlertManager.ALERT_TYPE_HOST) && (alertType != AlertManager.ALERT_TYPE_USERVM) && diff --git a/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java b/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java index 8b2a1441151..0f454cdb582 100755 --- a/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java +++ b/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java @@ -18,12 +18,16 @@ package com.cloud.deploy; import javax.ejb.Local; +import org.apache.log4j.Logger; + import com.cloud.deploy.DeploymentPlanner.AllocationAlgorithm; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.vm.UserVmVO; @Local(value = {DeployPlannerSelector.class}) public class HypervisorVmPlannerSelector extends AbstractDeployPlannerSelector { + private static final Logger s_logger = Logger.getLogger(HypervisorVmPlannerSelector.class); + @Override public String selectPlanner(UserVmVO vm) { if (vm.getHypervisorType() != HypervisorType.BareMetal) { @@ -38,6 +42,10 @@ public class HypervisorVmPlannerSelector extends AbstractDeployPlannerSelector { || _allocationAlgorithm.equals(AllocationAlgorithm.userconcentratedpod_firstfit.toString())) { return "UserConcentratedPodPlanner"; } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("The allocation algorithm is null, cannot select the planner"); + } } } diff --git a/server/src/com/cloud/event/ActionEventInterceptor.java b/server/src/com/cloud/event/ActionEventInterceptor.java index fb89498ffce..a6c2565510e 100644 --- a/server/src/com/cloud/event/ActionEventInterceptor.java +++ b/server/src/com/cloud/event/ActionEventInterceptor.java @@ -19,22 +19,29 @@ package com.cloud.event; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import org.apache.log4j.Logger; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.reflect.MethodSignature; import com.cloud.user.UserContext; +import com.cloud.utils.component.ComponentMethodProxyCache; public class ActionEventInterceptor { + private static final Logger s_logger = Logger.getLogger(ActionEventInterceptor.class); public ActionEventInterceptor() { } public Object AroundAnyMethod(ProceedingJoinPoint call) throws Throwable { MethodSignature methodSignature = (MethodSignature)call.getSignature(); - Method targetMethod = methodSignature.getMethod(); - if(needToIntercept(targetMethod)) { + + // Note: AOP for ActionEvent is triggered annotation, no need to check the annotation on method again + Method targetMethod = ComponentMethodProxyCache.getTargetMethod( + methodSignature.getMethod(), call.getTarget()); + + if(targetMethod != null) { EventVO event = interceptStart(targetMethod); - + boolean success = true; Object ret = null; try { @@ -49,6 +56,8 @@ public class ActionEventInterceptor { } } return ret; + } else { + s_logger.error("Unable to find the proxied method behind. Method: " + methodSignature.getMethod().getName()); } return call.proceed(); } diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 8c665ad1eee..3b0ec0f943b 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -106,10 +106,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.utils.script.Script; import com.cloud.uuididentity.dao.IdentityDao; -import org.apache.cloudstack.region.RegionVO; -import org.apache.cloudstack.region.dao.RegionDao; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; + @Component public class ConfigurationServerImpl extends ManagerBase implements ConfigurationServer { @@ -152,7 +149,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio public void persistDefaultValues() throws InternalErrorException { fixupScriptFileAttribute(); - + // Create system user and admin user saveUser(); @@ -337,23 +334,20 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio @DB protected void saveUser() { - int region_id = _configDao.getRegionId(); // insert system account - String insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, region_id) VALUES (1, UUID(), 'system', '1', '1', ?)"; + String insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id) VALUES (1, UUID(), 'system', '1', '1')"; Transaction txn = Transaction.currentTxn(); try { PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql); - stmt.setInt(1, region_id); stmt.executeUpdate(); } catch (SQLException ex) { } // insert system user - insertSql = "INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, lastname, created, region_id)" + - " VALUES (1, UUID(), 'system', RAND(), 1, 'system', 'cloud', now(), ?)"; + insertSql = "INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, lastname, created)" + + " VALUES (1, UUID(), 'system', RAND(), 1, 'system', 'cloud', now())"; txn = Transaction.currentTxn(); try { PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql); - stmt.setInt(1, region_id); stmt.executeUpdate(); } catch (SQLException ex) { } @@ -366,23 +360,21 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio String lastname = "cloud"; // create an account for the admin user first - insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, region_id) VALUES (" + id + ", UUID(), '" + username + "', '1', '1', ?)"; + insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id) VALUES (" + id + ", UUID(), '" + username + "', '1', '1')"; txn = Transaction.currentTxn(); try { PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql); - stmt.setInt(1, region_id); stmt.executeUpdate(); } catch (SQLException ex) { } // now insert the user - insertSql = "INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, lastname, created, state, region_id) " + - "VALUES (" + id + ", UUID(), '" + username + "', RAND(), 2, '" + firstname + "','" + lastname + "',now(), 'disabled', ?)"; + insertSql = "INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, lastname, created, state) " + + "VALUES (" + id + ", UUID(), '" + username + "', RAND(), 2, '" + firstname + "','" + lastname + "',now(), 'disabled')"; txn = Transaction.currentTxn(); try { PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql); - stmt.setInt(1, region_id); stmt.executeUpdate(); } catch (SQLException ex) { } @@ -708,15 +700,15 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio } } - + private void fixupScriptFileAttribute() { - // TODO : this is a hacking fix to workaround that executable bit is not preserved in WAR package + // TODO : this is a hacking fix to workaround that executable bit is not preserved in WAR package String scriptPath = Script.findScript("", "scripts/vm/systemvm/injectkeys.sh"); if(scriptPath != null) { File file = new File(scriptPath); if(!file.canExecute()) { s_logger.info("Some of the shell script files may not have executable bit set. Fixup..."); - + String cmd = "chmod ugo+x " + scriptPath; s_logger.info("Executing " + cmd); String result = Script.runSimpleBashScript(cmd); diff --git a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java index 5bd749fe842..8f9be0f5d57 100755 --- a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -162,6 +162,10 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker { _upgradeMap.put("4.0.0", new DbUpgrade[] { new Upgrade40to41(), new Upgrade410to420() }); + _upgradeMap.put("4.0.1", new DbUpgrade[] { new Upgrade40to41(), new Upgrade410to420() }); + + _upgradeMap.put("4.0.2", new DbUpgrade[] { new Upgrade40to41(), new Upgrade410to420() }); + _upgradeMap.put("4.1.0", new DbUpgrade[] { new Upgrade410to420() }); } diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java index 6815b0d43bc..297e71118ad 100644 --- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java +++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java @@ -53,7 +53,7 @@ public class ConsoleProxyHttpHandlerHelper { ConsoleProxyClientParam param = encryptor.decryptObject(ConsoleProxyClientParam.class, map.get("token")); // make sure we get information from token only - map.clear(); + guardUserInput(map); if(param != null) { if(param.getClientHostAddress() != null) map.put("host", param.getClientHostAddress()); @@ -72,9 +72,19 @@ public class ConsoleProxyHttpHandlerHelper { } } else { // we no longer accept information from parameter other than token - map.clear(); + guardUserInput(map); } return map; } + + private static void guardUserInput(Map map) { + map.remove("host"); + map.remove("port"); + map.remove("tag"); + map.remove("sid"); + map.remove("consoleurl"); + map.remove("sessionref"); + map.remove("ticket"); + } } diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index 865fbd3181c..0f316a5acdd 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -261,7 +261,7 @@ CREATE TABLE `cloud`.`region` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `cloud`.`region` values ('1','Local','http://localhost:8080/client/api'); +INSERT INTO `cloud`.`region` values ('1','Local','http://localhost:8080/client'); INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Account Defaults', 'DEFAULT', 'management-server', 'max.account.cpus', '40', 'The default maximum number of cpu cores that can be used for an account'); diff --git a/tools/cli/cloudmonkey/__init__.py b/tools/cli/cloudmonkey/__init__.py index e4c4e6d24f1..cf689e79480 100644 --- a/tools/cli/cloudmonkey/__init__.py +++ b/tools/cli/cloudmonkey/__init__.py @@ -16,6 +16,8 @@ # under the License. try: - from config import __version__ + from config import __version__, __description__ + from config import __maintainer__, __maintaineremail__ + from config import __project__, __projecturl__, __projectemail__ except ImportError, e: print e diff --git a/tools/cli/cloudmonkey/cachemaker.py b/tools/cli/cloudmonkey/cachemaker.py index 42a077ad928..8ac123caa4b 100644 --- a/tools/cli/cloudmonkey/cachemaker.py +++ b/tools/cli/cloudmonkey/cachemaker.py @@ -21,7 +21,7 @@ try: import os import types - from config import cache_file + from config import config_fields except ImportError, e: import sys print "ImportError", e @@ -168,6 +168,7 @@ def main(json_file): f.close() if __name__ == "__main__": + cache_file = config_fields['core']['cache_file'] print "[cachemaker] Pre-caching using user's cloudmonkey cache", cache_file if os.path.exists(cache_file): main(cache_file) diff --git a/tools/cli/cloudmonkey/cloudmonkey.py b/tools/cli/cloudmonkey/cloudmonkey.py index 25422412613..f750c3afa8d 100644 --- a/tools/cli/cloudmonkey/cloudmonkey.py +++ b/tools/cli/cloudmonkey/cloudmonkey.py @@ -29,8 +29,9 @@ try: import types from cachemaker import loadcache, savecache, monkeycache, splitverbsubject - from config import __version__, cache_file - from config import read_config, write_config + from config import __version__, __description__, __projecturl__ + from config import read_config, write_config, config_file + from optparse import OptionParser from prettytable import PrettyTable from printer import monkeyprint from requester import monkeyrequest @@ -63,13 +64,14 @@ class CloudMonkeyShell(cmd.Cmd, object): intro = ("☁ Apache CloudStack 🐵 cloudmonkey " + __version__ + ". Type help or ? to list commands.\n") ruler = "=" - cache_file = cache_file config_options = [] verbs = [] - def __init__(self, pname): + def __init__(self, pname, cfile): self.program_name = pname - self.config_options = read_config(self.get_attr, self.set_attr) + self.config_file = cfile + self.config_options = read_config(self.get_attr, self.set_attr, + self.config_file) self.loadcache() self.prompt = self.prompt.strip() + " " # Cosmetic fix for prompt @@ -364,7 +366,7 @@ class CloudMonkeyShell(cmd.Cmd, object): key, value = (args[0], args[2]) setattr(self, key, value) # keys and attributes should have same names self.prompt = self.prompt.strip() + " " # prompt fix - write_config(self.get_attr) + write_config(self.get_attr, self.config_file) def complete_set(self, text, line, begidx, endidx): mline = line.partition(" ")[2] @@ -458,10 +460,37 @@ class CloudMonkeyShell(cmd.Cmd, object): return self.do_EOF(args) +class MonkeyParser(OptionParser): + def format_help(self, formatter=None): + if formatter is None: + formatter = self.formatter + result = [] + if self.usage: + result.append("Usage: cloudmonkey [options] [cmds] [params]\n\n") + if self.description: + result.append(self.format_description(formatter) + "\n") + result.append(self.format_option_help(formatter)) + result.append("\nTry cloudmonkey [help|?]\n") + return "".join(result) + + def main(): - shell = CloudMonkeyShell(sys.argv[0]) + parser = MonkeyParser() + parser.add_option("-c", "--config-file", + dest="cfile", default=config_file, + help="config file for cloudmonkey", metavar="FILE") + parser.add_option("-v", "--version", + action="store_true", dest="version", default=False, + help="prints cloudmonkey version information") + + (options, args) = parser.parse_args() + if options.version: + print "cloudmonkey", __version__ + print __description__, "(%s)" % __projecturl__ + + shell = CloudMonkeyShell(sys.argv[0], options.cfile) if len(sys.argv) > 1: - shell.onecmd(' '.join(sys.argv[1:])) + shell.onecmd(' '.join(args)) else: shell.cmdloop() diff --git a/tools/cli/cloudmonkey/config.py b/tools/cli/cloudmonkey/config.py index 6a5feab8d12..4a4aa99cdc8 100644 --- a/tools/cli/cloudmonkey/config.py +++ b/tools/cli/cloudmonkey/config.py @@ -19,6 +19,12 @@ # Use following rules for versioning: # - __version__ = "4.1.0-0" +__description__ = "Command Line Interface for Apache CloudStack" +__maintainer__ = "Rohit Yadav" +__maintaineremail__ = "bhaisaab@apache.org" +__project__ = "The Apache CloudStack Team" +__projectemail__ = "cloudstack-dev@incubator.apache.org" +__projecturl__ = "http://incubator.apache.org/cloudstack" try: import os @@ -36,14 +42,14 @@ iterable_type = ['set', 'list', 'object'] config_dir = expanduser('~/.cloudmonkey') config_file = expanduser(config_dir + '/config') -cache_file = expanduser(config_dir + '/cache') # cloudmonkey config fields -config_fields = {'core': {}, 'ui': {}, 'server': {}, 'user': {}} +config_fields = {'core': {}, 'server': {}, 'user': {}, 'ui': {}} # core config_fields['core']['asyncblock'] = 'true' config_fields['core']['paramcompletion'] = 'false' +config_fields['core']['cache_file'] = expanduser(config_dir + '/cache') config_fields['core']['history_file'] = expanduser(config_dir + '/history') config_fields['core']['log_file'] = expanduser(config_dir + '/log') @@ -64,8 +70,8 @@ config_fields['user']['apikey'] = '' config_fields['user']['secretkey'] = '' -def write_config(get_attr, first_time=False): - global config_fields, config_file +def write_config(get_attr, config_file, first_time=False): + global config_fields config = ConfigParser() for section in config_fields.keys(): config.add_section(section) @@ -79,8 +85,8 @@ def write_config(get_attr, first_time=False): return config -def read_config(get_attr, set_attr): - global config_fields, config_dir, config_file +def read_config(get_attr, set_attr, config_file): + global config_fields, config_dir if not os.path.exists(config_dir): os.makedirs(config_dir) @@ -95,7 +101,7 @@ def read_config(get_attr, set_attr): except IOError, e: print "Error: config_file not found", e else: - config = write_config(get_attr, True) + config = write_config(get_attr, config_file, True) print "Welcome! Using `set` configure the necessary settings:" print " ".join(sorted(config_options)) print "Config file:", config_file diff --git a/tools/cli/setup.py b/tools/cli/setup.py index 9624115ed5f..4c7b2978b2f 100644 --- a/tools/cli/setup.py +++ b/tools/cli/setup.py @@ -22,13 +22,9 @@ except ImportError: use_setuptools() from setuptools import setup, find_packages -from cloudmonkey import __version__ - -name = 'cloudmonkey' -version = __version__ -requires = ['Pygments>=1.5', - 'prettytable>=0.6', - ] +from cloudmonkey import __version__, __description__ +from cloudmonkey import __maintainer__, __maintaineremail__ +from cloudmonkey import __project__, __projecturl__, __projectemail__ try: import readline @@ -36,20 +32,22 @@ except ImportError: requires.append('readline') setup( - name = name, - version = version, - author = "The Apache CloudStack Team", - author_email = "cloudstack-dev@incubator.apache.org", - maintainer = "Rohit Yadav", - maintainer_email = "bhaisaab@apache.org", - url = "http://incubator.apache.org/cloudstack", - description = "Command Line Interface for Apache CloudStack", - long_description = "cloudmonkey is a command line interface for Apache " - "CloudStack powered by CloudStack Marvin", + name = 'cloudmonkey', + version = __version__, + author = __project__, + author_email = __projectemail__, + maintainer = __maintainer__, + maintainer_email = __maintaineremail__, + url = __projecturl__, + description = __description__, + long_description = "cloudmonkey is a CLI for Apache CloudStack", platforms = ("Any",), license = 'ASL 2.0', packages = find_packages(), - install_requires = requires, + install_requires = [ + 'Pygments>=1.5', + 'prettytable>=0.6', + ], include_package_data = True, zip_safe = False, classifiers = [ diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index ad26b34196e..8bcdff91574 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -400,20 +400,28 @@ cloudStack.converters = { case 4 : return _l('label.public.ips'); case 5 : return _l('label.management.ips'); case 6 : return _l('label.secondary.storage'); - case 7 : return _l('label.vlan'); - case 8 : return _l('label.direct.ips'); - case 9 : return _l('label.local.storage'); + case 7 : return _l('label.host'); + case 9 : return _l('label.domain.router'); + case 10 : return _l('label.console.proxy'); - // These are old values -- can be removed in the future - case 10 : return "Routing Host"; - case 11 : return "Storage"; - case 12 : return "Usage Server"; - case 13 : return "Management Server"; - case 14 : return "Domain Router"; - case 15 : return "Console Proxy"; - case 16 : return "User VM"; - case 17 : return "VLAN"; - case 18 : return "Secondary Storage VM"; + // These are old values -- can be removed in the future + case 8 : return "User VM"; + case 11 : return "Routing Host"; + case 12 : return "Storage"; + case 13 : return "Usage Server"; + case 14 : return "Management Server"; + case 15 : return "Domain Router"; + case 16 : return "Console Proxy"; + case 17 : return "User VM"; + case 18 : return "VLAN"; + case 19 : return "Secondary Storage VM"; + case 20 : return "Usage Server"; + case 21 : return "Storage"; + case 22 : return "Update Resource Count"; + case 23 : return "Usage Sanity Result"; + case 24 : return "Direct Attached Public IP"; + case 25 : return "Local Storage"; + case 26 : return "Resource Limit Exceeded"; } }, convertByType: function(alertCode, value) { diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 4d529aeb04e..c0a5d141700 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -7597,7 +7597,7 @@ if(vSwitchEnabled) { - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); @@ -7610,7 +7610,7 @@ else{ items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } args.response.success({data: items}); diff --git a/ui/scripts/ui-custom/healthCheck.js b/ui/scripts/ui-custom/healthCheck.js index c4c84e5236b..ebb7e5a8903 100644 --- a/ui/scripts/ui-custom/healthCheck.js +++ b/ui/scripts/ui-custom/healthCheck.js @@ -73,7 +73,7 @@ form: { title: '', fields:{ - pingpath: {label: 'Ping Path', docID:'helpAccountUsername' , validation: {required: false}, defaultValue: pingpath1} + pingpath: {label: 'Ping Path', validation: {required: false}, defaultValue: pingpath1} } } }); diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index 47932664927..5108c5c0c3b 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -897,7 +897,7 @@ if(vSwitchEnabled) { - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); @@ -909,9 +909,9 @@ // items.push({id: " ", description: " "}); else{ - items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({id:"vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); + items.push({ id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } args.response.success({data: items}); diff --git a/usage/src/com/cloud/usage/UsageAlertManagerImpl.java b/usage/src/com/cloud/usage/UsageAlertManagerImpl.java index a0765b2b272..dc918b83b6d 100644 --- a/usage/src/com/cloud/usage/UsageAlertManagerImpl.java +++ b/usage/src/com/cloud/usage/UsageAlertManagerImpl.java @@ -50,11 +50,12 @@ import com.sun.mail.smtp.SMTPTransport; @Local(value={AlertManager.class}) public class UsageAlertManagerImpl extends ManagerBase implements AlertManager { private static final Logger s_logger = Logger.getLogger(UsageAlertManagerImpl.class.getName()); + private static final Logger s_alertsLogger = Logger.getLogger("org.apache.cloudstack.alerts"); private EmailAlert _emailAlert; @Inject private AlertDao _alertDao; @Inject private ConfigurationDao _configDao; - + @Override public boolean configure(String name, Map params) throws ConfigurationException { Map configs = _configDao.getConfiguration("management-server", params); @@ -101,6 +102,9 @@ public class UsageAlertManagerImpl extends ManagerBase implements AlertManager { try { if (_emailAlert != null) { _emailAlert.sendAlert(alertType, dataCenterId, podId, subject, body); + } else { + s_alertsLogger.warn(" alertType:: " + alertType + " // dataCenterId:: " + dataCenterId + " // podId:: " + + podId + " // clusterId:: " + null + " // message:: " + subject ); } } catch (Exception ex) { s_logger.error("Problem sending email alert", ex); @@ -171,18 +175,19 @@ public class UsageAlertManagerImpl extends ManagerBase implements AlertManager { // TODO: make sure this handles SSL transport (useAuth is true) and regular public void sendAlert(short alertType, long dataCenterId, Long podId, String subject, String content) throws MessagingException, UnsupportedEncodingException { + s_alertsLogger.warn(" alertType:: " + alertType + " // dataCenterId:: " + dataCenterId + " // podId:: " + + podId + " // clusterId:: " + null + " // message:: " + subject); AlertVO alert = null; - if ((alertType != AlertManager.ALERT_TYPE_HOST) && (alertType != AlertManager.ALERT_TYPE_USERVM) && (alertType != AlertManager.ALERT_TYPE_DOMAIN_ROUTER) && (alertType != AlertManager.ALERT_TYPE_CONSOLE_PROXY) && - (alertType != AlertManager.ALERT_TYPE_SSVM) && + (alertType != AlertManager.ALERT_TYPE_SSVM) && (alertType != AlertManager.ALERT_TYPE_STORAGE_MISC) && (alertType != AlertManager.ALERT_TYPE_MANAGMENT_NODE)) { alert = _alertDao.getLastAlert(alertType, dataCenterId, podId); } - + if (alert == null) { // set up a new alert AlertVO newAlert = new AlertVO(); diff --git a/utils/src/com/cloud/utils/component/AdapterBase.java b/utils/src/com/cloud/utils/component/AdapterBase.java index a8f4f468090..ea5e9611ab6 100644 --- a/utils/src/com/cloud/utils/component/AdapterBase.java +++ b/utils/src/com/cloud/utils/component/AdapterBase.java @@ -22,8 +22,10 @@ import java.util.List; public class AdapterBase extends ComponentLifecycleBase implements Adapter { public AdapterBase() { + // set default run level for adapter components + setRunLevel(ComponentLifecycle.RUN_LEVEL_COMPONENT); } - + public static T getAdapterByName(List adapters, String name) { for(T adapter : adapters) { if(adapter.getName() != null && adapter.getName().equalsIgnoreCase(name)) diff --git a/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java b/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java new file mode 100644 index 00000000000..ea3b68573cf --- /dev/null +++ b/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java @@ -0,0 +1,90 @@ +// 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 +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.utils.component; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.util.WeakHashMap; + +public class ComponentMethodProxyCache { + + private static WeakHashMap> s_cache = new WeakHashMap>(); + + public ComponentMethodProxyCache() { + } + + public static Method getTargetMethod(Method method, Object target) { + synchronized(s_cache) { + WeakReference targetMethod = s_cache.get(new TargetKey(method, target)); + if(targetMethod != null && targetMethod.get() != null) + return targetMethod.get(); + + Class clazz = target.getClass(); + for(Method m : clazz.getMethods()) { + if(isMethodMatched(method, m)) { + s_cache.put(new TargetKey(method, target), new WeakReference(m)); + return m; + } + } + + return method; + } + } + + private static boolean isMethodMatched(Method m1, Method m2) { + if(!m1.getName().equals(m2.getName())) + return false; + + Class[] params1 = m1.getParameterTypes(); + Class[] params2 = m2.getParameterTypes(); + + if(params1.length != params2.length) + return false; + + for(int i = 0; i < params1.length; i++) { + if(!params1[i].isAssignableFrom(params2[i])) + return false; + } + + return true; + } + + public static class TargetKey { + Method _method; + Object _target; + + public TargetKey(Method method, Object target) { + _method = method; + _target = target; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof TargetKey)) + return false; + + // for target object, we just check the reference + return _method.equals(((TargetKey)obj)._method) && + _target == ((TargetKey)obj)._target; + } + + public int hashCode() { + return _target.hashCode() ^ _target.hashCode(); + } + } +} diff --git a/utils/src/com/cloud/utils/component/SpringComponentScanUtils.java b/utils/src/com/cloud/utils/component/SpringComponentScanUtils.java index fda11b74609..9a85c79fa80 100644 --- a/utils/src/com/cloud/utils/component/SpringComponentScanUtils.java +++ b/utils/src/com/cloud/utils/component/SpringComponentScanUtils.java @@ -38,5 +38,4 @@ public class SpringComponentScanUtils { } return false; } - } diff --git a/utils/src/com/cloud/utils/db/TransactionContextBuilder.java b/utils/src/com/cloud/utils/db/TransactionContextBuilder.java index e03b25f912d..7ca33ab5f5d 100644 --- a/utils/src/com/cloud/utils/db/TransactionContextBuilder.java +++ b/utils/src/com/cloud/utils/db/TransactionContextBuilder.java @@ -22,9 +22,10 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.log4j.Logger; import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.Signature; import org.aspectj.lang.reflect.MethodSignature; +import com.cloud.utils.component.ComponentMethodProxyCache; + public class TransactionContextBuilder implements MethodInterceptor { private static final Logger s_logger = Logger.getLogger(TransactionContextBuilder.class); public TransactionContextBuilder() { @@ -72,14 +73,9 @@ public class TransactionContextBuilder implements MethodInterceptor { Class clazz = method.getDeclaringClass(); if(clazz.isInterface()) { clazz = target.getClass(); - for(Method m : clazz.getMethods()) { - // it is supposed that we need to check against type arguments, - // this can be simplified by just checking method name - if(m.getName().equals(method.getName())) { - if(m.getAnnotation(DB.class) != null) - return true; - } - } + Method targetMethod = ComponentMethodProxyCache.getTargetMethod(method, target); + if(targetMethod != null && targetMethod.getAnnotation(DB.class) != null) + return true; } do {