diff --git a/api/src/com/cloud/agent/api/to/MonitorServiceTO.java b/api/src/com/cloud/agent/api/to/MonitorServiceTO.java new file mode 100644 index 00000000000..deced16eff9 --- /dev/null +++ b/api/src/com/cloud/agent/api/to/MonitorServiceTO.java @@ -0,0 +1,74 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api.to; + +import org.apache.cloudstack.api.InternalIdentity; + +public class MonitorServiceTO implements InternalIdentity { + long id; + String service; + String processname; + String serviceName; + String servicePath; + String pidFile; + boolean isDefault; + + protected MonitorServiceTO() { + } + + public MonitorServiceTO (String service, String processname, String serviceName, String servicepath, String pidFile, boolean isDefault) { + this.service = service; + this.processname = processname; + this.serviceName = serviceName; + this.servicePath = servicepath; + this.pidFile = pidFile; + this.isDefault = isDefault; + } + + + + public boolean isDefault() { + return isDefault; + } + + public String getPidFile() { + return pidFile; + } + + @Override + public long getId() { + return id; + } + + + public String getService() { + return service; + } + + public String getServiceName() { + return serviceName; + } + + public String getServicePath() { + return servicePath; + } + + public String getProcessname() { + return processname; + } + +} diff --git a/api/src/com/cloud/network/MonitoringService.java b/api/src/com/cloud/network/MonitoringService.java new file mode 100644 index 00000000000..2a1754ab970 --- /dev/null +++ b/api/src/com/cloud/network/MonitoringService.java @@ -0,0 +1,42 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + + +/** + * Nic represents one nic on the VM. + */ +public interface MonitoringService extends ControlledEntity, Identity, InternalIdentity { + /** + * @return id in the CloudStack database + */ + enum Service { + Dhcp, + LoadBalancing, + Ssh, + Webserver, + } + long getId(); + String getService(); + String getServiceName(); + String getPidFile(); + String getServicePath(); +} diff --git a/core/src/com/cloud/agent/api/routing/SetMonitorServiceCommand.java b/core/src/com/cloud/agent/api/routing/SetMonitorServiceCommand.java new file mode 100644 index 00000000000..109daf2c2b6 --- /dev/null +++ b/core/src/com/cloud/agent/api/routing/SetMonitorServiceCommand.java @@ -0,0 +1,56 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api.routing; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import com.cloud.agent.api.to.MonitorServiceTO; + +/** + * + * AccessDetails allow different components to put in information about + * how to access the components inside the command. + */ +public class SetMonitorServiceCommand extends NetworkElementCommand { + MonitorServiceTO[] services; + + protected SetMonitorServiceCommand() { + } + + public SetMonitorServiceCommand(List services) { + this.services = services.toArray(new MonitorServiceTO[services.size()]); + } + + public MonitorServiceTO[] getRules() { + return services; + } + + public String getConfiguration() { + + StringBuilder sb = new StringBuilder(); + for (MonitorServiceTO service: services) { + sb.append("[").append(service.getService()).append("]").append(":"); + sb.append("processname=").append(service.getProcessname()).append(":"); + sb.append("servicename=").append(service.getServiceName()).append(":"); + sb.append("pidfile=").append(service.getPidFile()).append(":"); + sb.append(","); + } + + return sb.toString(); + } +} diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index e811cce2362..98ef018d791 100644 --- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -155,6 +155,7 @@ + diff --git a/engine/schema/src/com/cloud/network/dao/MonitoringServiceDao.java b/engine/schema/src/com/cloud/network/dao/MonitoringServiceDao.java new file mode 100644 index 00000000000..7cc7cc08b68 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/MonitoringServiceDao.java @@ -0,0 +1,31 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.dao; + +import com.cloud.utils.db.GenericDao; + +import java.util.List; + +public interface MonitoringServiceDao extends GenericDao { + + List listAllServices(); + List listDefaultServices(boolean isDefault); + + MonitoringServiceVO getServiceByName(String service); + +} diff --git a/engine/schema/src/com/cloud/network/dao/MonitoringServiceDaoImpl.java b/engine/schema/src/com/cloud/network/dao/MonitoringServiceDaoImpl.java new file mode 100644 index 00000000000..53dc7d455bb --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/MonitoringServiceDaoImpl.java @@ -0,0 +1,68 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + + + +package com.cloud.network.dao; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.List; + +@Component +@Local(value=MonitoringServiceDao.class) +public class MonitoringServiceDaoImpl extends GenericDaoBase implements MonitoringServiceDao { + private final SearchBuilder AllFieldsSearch; + + public MonitoringServiceDaoImpl() { + super(); + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("isDefault", AllFieldsSearch.entity().getDefault(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("service", AllFieldsSearch.entity().getService(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("processname", AllFieldsSearch.entity().getProcessname(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("servicename", AllFieldsSearch.entity().getServiceName(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("servicepath", AllFieldsSearch.entity().getServicePath(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("servicePidFile", AllFieldsSearch.entity().getPidFile(), SearchCriteria.Op.EQ); + + AllFieldsSearch.done(); + } + + + + @Override + public List listAllServices() { + return null; + } + + @Override + public List listDefaultServices(boolean isDefault) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("isDefault", isDefault); + return listBy(sc); + } + + @Override + public MonitoringServiceVO getServiceByName(String service) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("service", service); + return findOneBy(sc); + } +} \ No newline at end of file diff --git a/engine/schema/src/com/cloud/network/dao/MonitoringServiceVO.java b/engine/schema/src/com/cloud/network/dao/MonitoringServiceVO.java new file mode 100644 index 00000000000..3f9122cec73 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/MonitoringServiceVO.java @@ -0,0 +1,119 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import com.cloud.network.MonitoringService; + +import javax.persistence.*; +import java.util.UUID; + +@Entity +@Table(name = "monitoring_services") +public class MonitoringServiceVO implements MonitoringService { + + public MonitoringServiceVO(String service, String processname, String serviceName, String servicePath, + String pidFile) { + this.service = service; + this.processname = processname; + this.servicename = serviceName; + this.servicePath = servicePath; + this.servicePidFile= pidFile; + + } + + protected MonitoringServiceVO() { + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + long id; + + @Column(name = "service") + String service; + + @Column(name="process_name", updatable=false) + String processname; + + @Column(name="service_name", updatable=false) + String servicename; + + @Column(name="service_path", updatable=false) + private String servicePath; + + @Column(name="pidFile", updatable=false) + private String servicePidFile; + + @Column(name="isDefault") + private boolean isDefault; + + + @Column(name = "uuid") + String uuid = UUID.randomUUID().toString(); + + public long getId() { + return id; + } + + @Override + public String getService() { + return this.service; + } + + @Override + public String getServiceName() { + return this.servicename; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public String getPidFile() { + return this.servicePidFile; + + } + + @Override + public String getServicePath() { + return this.servicePidFile; + } + + @Override + public String getUuid() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public long getAccountId() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public long getDomainId() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean getDefault() { + return isDefault; + } + + public void setDefault(boolean isDefault) { + isDefault = isDefault; + } + + public String getProcessname() { + return processname; + } +} diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 5c9f4e568d2..69b7c9e07c7 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -118,34 +118,7 @@ import com.cloud.agent.api.check.CheckSshCommand; import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.ConsoleProxyLoadAnswer; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; -import com.cloud.agent.api.routing.CreateIpAliasCommand; -import com.cloud.agent.api.routing.DeleteIpAliasCommand; -import com.cloud.agent.api.routing.DhcpEntryCommand; -import com.cloud.agent.api.routing.DnsMasqConfigCommand; -import com.cloud.agent.api.routing.IpAliasTO; -import com.cloud.agent.api.routing.IpAssocAnswer; -import com.cloud.agent.api.routing.IpAssocCommand; -import com.cloud.agent.api.routing.IpAssocVpcCommand; -import com.cloud.agent.api.routing.LoadBalancerConfigCommand; -import com.cloud.agent.api.routing.NetworkElementCommand; -import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; -import com.cloud.agent.api.routing.SavePasswordCommand; -import com.cloud.agent.api.routing.SetFirewallRulesAnswer; -import com.cloud.agent.api.routing.SetFirewallRulesCommand; -import com.cloud.agent.api.routing.SetNetworkACLAnswer; -import com.cloud.agent.api.routing.SetNetworkACLCommand; -import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer; -import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; -import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand; -import com.cloud.agent.api.routing.SetSourceNatAnswer; -import com.cloud.agent.api.routing.SetSourceNatCommand; -import com.cloud.agent.api.routing.SetStaticNatRulesAnswer; -import com.cloud.agent.api.routing.SetStaticNatRulesCommand; -import com.cloud.agent.api.routing.SetStaticRouteAnswer; -import com.cloud.agent.api.routing.SetStaticRouteCommand; -import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand; -import com.cloud.agent.api.routing.VmDataCommand; -import com.cloud.agent.api.routing.VpnUsersCfgCommand; +import com.cloud.agent.api.routing.*; import com.cloud.agent.api.storage.CopyVolumeAnswer; import com.cloud.agent.api.storage.CopyVolumeCommand; import com.cloud.agent.api.storage.CreateAnswer; @@ -633,6 +606,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return execute((ScaleVmCommand) cmd); } else if (clazz == PvlanSetupCommand.class) { return execute((PvlanSetupCommand) cmd); + } else if (clazz == SetMonitorServiceCommand.class) { + return execute((SetMonitorServiceCommand) cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } @@ -8121,6 +8096,30 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return new Answer(cmd, success, ""); } + private Answer execute(SetMonitorServiceCommand cmd) { + boolean success = true; + + String config = cmd.getConfiguration(); + + Connection conn = getConnection(); + String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); + + if (routerIp == null) { + return new Answer(cmd); + } + + String args = "monitor_service.sh " + routerIp; + args += " -c " + config; + + String result = callHostPlugin(conn, "vmops", "routerProxy", "args", args); + if (result == null || result.isEmpty()) { + return new Answer(cmd, false, "SetMonitorServiceCommand failed to create cfg file."); + } + + return new Answer(cmd, success, ""); + + } + protected SetFirewallRulesAnswer execute(SetFirewallRulesCommand cmd) { String[] results = new String[cmd.getRules().length]; String callResult; diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index a93480be56d..9b35a4b0fbd 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -41,6 +41,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.agent.api.to.*; import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -82,17 +83,12 @@ import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; import com.cloud.agent.api.routing.SavePasswordCommand; import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetMonitorServiceCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; import com.cloud.agent.api.routing.VmDataCommand; import com.cloud.agent.api.routing.VpnUsersCfgCommand; -import com.cloud.agent.api.to.DhcpTO; -import com.cloud.agent.api.to.FirewallRuleTO; -import com.cloud.agent.api.to.IpAddressTO; -import com.cloud.agent.api.to.LoadBalancerTO; -import com.cloud.agent.api.to.PortForwardingRuleTO; -import com.cloud.agent.api.to.StaticNatRuleTO; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.cluster.ClusterManager; @@ -164,6 +160,7 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.LoadBalancerVMMapDao; import com.cloud.network.dao.LoadBalancerVO; +import com.cloud.network.dao.MonitoringServiceVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; @@ -175,6 +172,7 @@ import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.network.dao.VirtualRouterProviderDao; import com.cloud.network.dao.VpnUserDao; +import com.cloud.network.dao.MonitoringServiceDao; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; @@ -183,6 +181,7 @@ import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualRouter.RedundantState; import com.cloud.network.router.VirtualRouter.Role; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.MonitoringService; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; @@ -369,8 +368,11 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V IpAddressManager _ipAddrMgr; @Inject ConfigDepot _configDepot; + @Inject + MonitoringServiceDao _monitorServiceDao; + + - int _routerRamSize; int _routerCpuMHz; int _retry = 2; @@ -2332,10 +2334,56 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V finalizeUserDataAndDhcpOnStart(cmds, router, provider, guestNetworkId); } + finalizeMonitorServiceOnStrat(cmds, router, provider, routerGuestNtwkIds.get(0)); return true; } + private void finalizeMonitorServiceOnStrat(Commands cmds, DomainRouterVO router, Provider provider, long networkId) { + + NetworkVO network = _networkDao.findById(networkId); + + s_logger.debug("Creating monitoring services on "+ router +" start..."); + + + // get the list of sevices for this network to monitor + List services = new ArrayList(); + if (_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, Provider.VirtualRouter) || + _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, Provider.VirtualRouter)) { + MonitoringServiceVO dhcpService = _monitorServiceDao.getServiceByName(MonitoringService.Service.Dhcp.toString()); + if (dhcpService != null) { + services.add(dhcpService); + } + } + + if (_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Lb, Provider.VirtualRouter)) { + MonitoringServiceVO lbService = _monitorServiceDao.getServiceByName(MonitoringService.Service.LoadBalancing.toString()); + if (lbService != null) { + services.add(lbService); + } + } + List defaultServices = _monitorServiceDao.listDefaultServices(true); + services.addAll(defaultServices); + + List servicesTO = new ArrayList(); + for (MonitoringServiceVO service: services) { + MonitorServiceTO serviceTO = new MonitorServiceTO( service.getService(), service.getProcessname(), service.getServiceName(), service.getServicePath(), + service.getPidFile(), service.getDefault()); + servicesTO.add(serviceTO); + } + + SetMonitorServiceCommand command = new SetMonitorServiceCommand(servicesTO); + command.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); + command.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, getRouterIpInNetwork(networkId, router.getId())); + command.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + + cmds.addCommand("monitor", command); + } + + + + + protected NicProfile getControlNic(VirtualMachineProfile profile) { DomainRouterVO router = _routerDao.findById(profile.getId()); DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId()); diff --git a/setup/db/db/schema-421to430.sql b/setup/db/db/schema-421to430.sql index 9fe56c08441..26e4abf2251 100644 --- a/setup/db/db/schema-421to430.sql +++ b/setup/db/db/schema-421to430.sql @@ -561,3 +561,18 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'manag 'Sets the attribute for uniquemembers within a group','uniquemember',NULL,NULL,0); UPDATE `cloud`.`volumes` SET display_volume=1 where id>0; + +create table `cloud`.`monitoring_services` ( +`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', +`uuid` varchar(40), `service` varchar(255) COMMENT 'Service name', +`process_name` varchar(255) COMMENT 'running process name', +`service_name` varchar(255) COMMENT 'exact name of the running service', +`service_path` varchar(255) COMMENT 'path of the service in system', +`pidfile` varchar(255) COMMENT 'path of the pid file of the service', +`isDefault` boolean COMMENT 'Default service', PRIMARY KEY (`id`) +); + +insert into cloud.monitoring_services(id, service, process_name, service_name, service_path, pidfile, isDefault) values(1,'ssh','sshd', 'ssh','/etc/init.d/ssh','/var/run/sshd.pid',true); +insert into cloud.monitoring_services(id, service, process_name, service_name, service_path, pidfile, isDefault) values(2,'dhcp','dnsmasq','dnsmasq','/etc/init.d/dnsmasq','/var/run/dnsmasq/dnsmasq.pid',false); +insert into cloud.monitoring_services(id, service, process_name, service_name, service_path, pidfile, isDefault) values(3,'loadbalancing','haproxy','haproxy','/etc/init.d/haproxy','/var/run/haproxy.pid',false); +insert into cloud.monitoring_services(id, service, process_name, service_name, service_path, pidfile, isDefault) values(4,'webserver','apache2','apache2','/etc/init.d/apache2','/var/run/apache2.pid', true); diff --git a/systemvm/patches/debian/config/opt/cloud/bin/monitor_service.sh b/systemvm/patches/debian/config/opt/cloud/bin/monitor_service.sh new file mode 100755 index 00000000000..a2b789cac8f --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/bin/monitor_service.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +# 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. + +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + +set -x +usage() { + printf "Usage: %s: -c config string \n" $(basename $0) >&2 +} + +configFile='/etc/monitor.conf' + +create_config() { +services=$1; +services_list=$(echo $services | cut -d, -f1- --output-delimiter=" "); + +echo "#Monitor services config" >$configFile + +for s in $services_list +do +service=$(echo $s | cut -d: -f1); +processname=$(echo $s | cut -d: -f2); +service_name=$(echo $s | cut -d: -f3); +pidfile=$(echo $s | cut -d: -f4); + +echo $service >> $configFile; +echo $processname >> $configFile +echo $service_name >> $configFile +echo $pidfile >> $configFile + + + +done + +} + +config=$2 + +#delete cron job before updating config file +crontab -l | grep -v monitorServices.py | crontab - + +create_config $config + +#add cron job +(crontab -l ; echo "*/3 * * * * python /root/monitorServices.py") | crontab - + + +unlock_exit 0 $lock $locked + diff --git a/systemvm/patches/debian/config/root/monitorServices.py b/systemvm/patches/debian/config/root/monitorServices.py new file mode 100755 index 00000000000..358c9dcdfac --- /dev/null +++ b/systemvm/patches/debian/config/root/monitorServices.py @@ -0,0 +1,263 @@ +#!/usr/bin/python +# 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. + + + + +__author__ = 'jayapalreddy' + +from ConfigParser import SafeConfigParser +from subprocess import * +from os import path +import time + +monitor_log='/var/log/monitor.log' +class StatusCodes: + SUCCESS = 0 + FAILED = 1 + INVALID_INP = 2 + RUNNING = 3 + STOPPED = 4 + STARTING = 5 + +class log: + INFO = 'INFO' + ALERT = 'ALERT' + CRIT = 'CRIT' + NOTIF = 'NOTIF' + + + + +def getConfig( config_file_path = "/etc/monitor.conf" ): + process_dict = {} + parser = SafeConfigParser() + parser.read( config_file_path ) + + #print 'Read values:\n' + + for section in parser.sections(): + # print section + process_dict[section] = {} + + for name, value in parser.items(section): + process_dict[section][name] = value +# print ' %s = %r' % (name, value) + + return process_dict + +def printd (msg): + return 0 + print msg + +def raisealert(severity, msg, process_name=None): + #timeStr=str(time.ctime()) + if process_name is not None: + log = '['+severity +']'+" " + '['+process_name+']' + " " + msg +"\n" + else: + log = '['+severity+']' + " " + msg +"\n" + + msg = 'logger -t monit '+ log + pout = Popen(msg, shell=True, stdout=PIPE) + + + #f= open(monitor_log,'r+') + #f.seek(0, 2) + #f.write(str(log)) + #f.close() + + +def isPidMatchPidFile(pidfile, pids): + + if pids is None or isinstance(pids,list) != True or len(pids) == 0: + print "Invalid Arguments" + return StatusCodes.FAILED + if not path.isfile(pidfile): + #It seems there is no pid file for this service + printd("The pid file "+pidfile+" is not there for this process") + return StatusCodes.FAILED + + fd=None + try: + fd = open(pidfile,'r') + except: + printd("pid file: "+ pidfile +" open failed") + return StatusCodes.FAILED + + + inp = fd.read() + printd("file content "+str(inp)) + printd(pids) + tocheck_pid = inp.strip() + for item in pids: + if str(tocheck_pid) == item.strip(): + printd("pid file matched") + return StatusCodes.SUCCESS + + fd.close() + return StatusCodes.FAILED + + + +def checkProcessStatus( process ): + process_name = process.get('processname') + service_name = process.get('servicename') + pidfile = process.get('pidfile') + #temp_out = None + restartFailed=0 + pidFileMatched=1 + cmd='' + if process_name is None: + print "\n Invalid Process Name" + return StatusCodes.INVALID_INP + else: + msg="checking the process " + process_name + printd(msg) + cmd = 'pidof ' + process_name + printd(cmd) + #cmd = 'service ' + process_name + ' status' + pout = Popen(cmd, shell=True, stdout=PIPE) + exitStatus = pout.wait() + temp_out = pout.communicate()[0] + + #check there is only one pid or not + if exitStatus == 0: + msg="pids: " +temp_out; + printd(msg) + pids = temp_out.split(' ') + + #there is more than one process so match the pid file + #if not matched set pidFileMatched=0 + printd("Checking pid file") + if isPidMatchPidFile(pidfile, pids) == StatusCodes.SUCCESS: + pidFileMatched = 1; + else: + pidFileMatched = 0; + + printd(pidFileMatched) + if exitStatus == 0 and pidFileMatched == 1: + printd("The process is running ....") + return StatusCodes.RUNNING + else: + printd('exit status:'+str(exitStatus)) + msg="The process " + process_name +" is not running trying recover " + printd(msg) + #Retry the process state for few seconds + for i in range(1,10): + pout = Popen(cmd, shell=True, stdout=PIPE) + exitStatus = pout.wait() + temp_out = pout.communicate()[0] + + if i < 5: # this is just for trying few more times + if exitStatus == 0: + pids = temp_out.split(' ') + + if isPidMatchPidFile(pidfile, pids) == StatusCodes.SUCCESS: + pidFileMatched = 1; + printd("pid file is matched ...") + raisealert(log.INFO, "The process detected as running", process_name) + break + else: + printd("pid file is not matched ...") + pidFileMatched = 0; + continue + time.sleep(1) + else: + msg="The process " +process_name+" is not running trying recover " + raisealert(log.INFO,process_name,msg) + + if service_name == 'apache2': + # Killing apache2 process with this the main service will not start + for pid in pids: + cmd = 'kill -9 '+pid; + printd(cmd) + Popen(cmd, shell=True, stdout=PIPE) + + cmd = 'service ' + service_name + ' restart' + try: + time.sleep(1) + return_val= check_call(cmd , shell=True) + except CalledProcessError: + restartFailed=1 + msg="service "+ process_name +" restart failed" + printd(msg) + continue + + if return_val == 0: + printd("The process" + process_name +" recovered successfully ") + msg="The process " +process_name+" is recovered successfully " + raisealert(log.ALERT,process_name,msg) + + break; + else: + #retry restarting the process for few tries + printd("process restart failing trying again ....") + restartFailed=1 + time.sleep(1) + continue + #for end here + + if restartFailed == 1: + msg="The process %s recover failed ", process_name; + raisealert(log.ALERT,process_name,msg) + + printd("Restart failed after number of retries") + return StatusCodes.STOPPED + + return StatusCodes.RUNNING + +def raiseAlert( process_name ): + print "process name %s is raised "%process_name + +def monitProcess( processes_info ): + if len( processes_info ) == 0: + print "Invalid Input" + return StatusCodes.INVALID_INP + for process,properties in processes_info.items(): + if checkProcessStatus( properties) != StatusCodes.RUNNING: + print "\n Process %s is not Running"%process + + +def main(): + ''' + Step1 : Get Config + ''' + + printd("monitoring started") + temp_dict = getConfig() + + ''' + Step2: Get Previous Run Log + ''' + + ''' + Step3: Monitor and Raise Alert + ''' + #raisealert(log.INFO, 'Monit started') + monitProcess( temp_dict ) + + +if __name__ == "__main__": + main() + + + + + + +