/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.plugins.samba; import java.util.List; import java.util.Set; import net.augeas.Augeas; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.MeasurementDataNumeric; import org.rhq.core.domain.measurement.MeasurementReport; import org.rhq.core.domain.measurement.MeasurementScheduleRequest; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; import org.rhq.core.pluginapi.inventory.CreateResourceReport; import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; import org.rhq.core.pluginapi.inventory.ResourceComponent; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.measurement.MeasurementFacet; import org.rhq.core.pluginapi.operation.OperationFacet; import org.rhq.core.pluginapi.operation.OperationResult; import org.rhq.core.pluginapi.util.ObjectUtil; import org.rhq.core.system.NetworkStats; import org.rhq.core.system.ProcessExecution; import org.rhq.core.system.ProcessExecutionResults; import org.rhq.core.system.ProcessInfo; import org.rhq.core.system.SystemInfo; import org.rhq.plugins.augeas.AugeasConfigurationComponent; import org.rhq.plugins.augeas.helper.AugeasNode; /** * TODO */ public class SambaServerComponent extends AugeasConfigurationComponent<ResourceComponent<?>> implements OperationFacet, MeasurementFacet { static final String ENABLE_RECYCLING = "enableRecycleBin"; static final String AUTHCONFIG_PATH = "/usr/bin/authconfig"; static final String NET_PATH = "/usr/bin/net"; static final String SPACE = " "; private static final int PORT = 445; private ProcessInfo processInfo; private ResourceContext resourceContext; public void start(ResourceContext resourceContext) throws Exception { this.resourceContext = resourceContext; super.start(resourceContext); getProcess(); } public void stop() { super.stop(); } public AvailabilityType getAvailability() { return super.getAvailability(); } public Configuration loadResourceConfiguration() throws Exception { return super.loadResourceConfiguration(); } public void updateResourceConfiguration(ConfigurationUpdateReport report) { super.updateResourceConfiguration(report); } @Override public CreateResourceReport createResource(CreateResourceReport reportIn) { CreateResourceReport report = reportIn; Configuration config = report.getResourceConfiguration(); String name = config.getSimple(SambaShareComponent.NAME_RESOURCE_CONFIG_PROP).getStringValue(); report.setResourceKey(name); report.setResourceName(name); return super.createResource(report); } @Override protected String getChildResourceConfigurationRootPath(ResourceType resourceType, Configuration resourceConfig) { if (resourceType.getName().equals(SambaShareComponent.RESOURCE_TYPE_NAME)) { String targetName = resourceConfig.getSimple(SambaShareComponent.NAME_RESOURCE_CONFIG_PROP) .getStringValue(); return "/files/etc/samba/smb.conf/target[.='" + targetName + "']"; } else { throw new IllegalArgumentException("Unsupported child Resource type: " + resourceType); } } @Override protected String getChildResourceConfigurationRootLabel(ResourceType resourceType, Configuration resourceConfig) { if (resourceType.getName().equals(SambaShareComponent.RESOURCE_TYPE_NAME)) { return resourceConfig.getSimple(SambaShareComponent.NAME_RESOURCE_CONFIG_PROP).getStringValue(); } else { throw new IllegalArgumentException("Unsupported child Resource type: " + resourceType); } } @Override protected void setNodeFromPropertySimple(Augeas augeas, AugeasNode node, PropertyDefinitionSimple propDefSimple, PropertySimple propSimple) { if (ENABLE_RECYCLING.equals(propDefSimple.getName())) { if (propSimple.getBooleanValue()) { String path = node.getParent().getPath(); augeas.set(path + "/vfs\\ objects", "recycle"); augeas.set(path + "/recycle:repository", ".recycle"); augeas.set(path + "/recycle:keeptree", "yes"); augeas.set(path + "/recycle:versions", "yes"); } else { String path = node.getParent().getPath(); augeas.remove(path + "/vfs\\ objects"); augeas.remove(path + "/recycle:repository"); augeas.remove(path + "/recycle:keeptree"); augeas.remove(path + "/recycle:versions"); } } else { super.setNodeFromPropertySimple(augeas, node, propDefSimple, propSimple); } } protected Object toPropertyValue(PropertyDefinitionSimple propDefSimple, Augeas augeas, AugeasNode node) { if (ENABLE_RECYCLING.equals(propDefSimple.getName())) { return "recycle".equals(augeas.get(node.getParent().getPath() + "/vfs\\ objects")); } return super.toPropertyValue(propDefSimple, augeas, node); } private void getProcess() { List<ProcessInfo> procs = resourceContext.getSystemInformation().getProcesses( "process|basename|match=smbd,process|basename|nomatch|parent=smbd"); if (procs.size() == 1) { this.processInfo = procs.get(0).getAggregateProcessTree(); } } public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { NetworkStats stats = resourceContext.getSystemInformation().getNetworkStats("localhost", PORT); if (processInfo != null) { processInfo.refresh(); for (MeasurementScheduleRequest request : metrics) { if (request.getName().startsWith("NetworkStat.")) { int val = stats.getByName(request.getName().substring("NetworkStat.".length())); report.addData(new MeasurementDataNumeric(request, (double) val)); } else if (request.getName().startsWith("Process.")) { Double value = ObjectUtil.lookupDeepNumericAttributeProperty(processInfo, request.getName() .substring("Process.".length())); report.addData(new MeasurementDataNumeric(request, value)); } } } } public OperationResult invokeOperation(String name, Configuration params) throws Exception { OperationResult result = null; if (name.equals("join")) { result = updateSmbAds(params); } else if (name.equals("disconnect")) { result = disconnectSmbAds(params); } return result; } private OperationResult disconnectSmbAds(Configuration params) throws Exception { Configuration resourceConfig = this.loadResourceConfiguration(); OperationResult result = new OperationResult(); String username = resourceConfig.getSimple("username").getStringValue(); String password = resourceConfig.getSimple("password").getStringValue(); if (username == null || password == null) { result.setSimpleResult("Missing required connection parameters"); return result; } StringBuilder netArgs = new StringBuilder(); netArgs.append("ads leave"); netArgs.append(SPACE + "-U " + username + "%" + password); ProcessExecutionResults netResults = execute(NET_PATH, netArgs.toString()); String results = netResults.getCapturedOutput(); result.setSimpleResult(results); return result; } private OperationResult updateSmbAds(Configuration params) throws Exception { Configuration resourceConfig = this.loadResourceConfiguration(); OperationResult result = new OperationResult(); String realm = resourceConfig.getSimple("realm").getStringValue(); String controller = resourceConfig.getSimple("controller").getStringValue(); String username = resourceConfig.getSimple("username").getStringValue(); String password = resourceConfig.getSimple("password").getStringValue(); String workgroup = resourceConfig.getSimple("workgroup").getStringValue(); String idmapuid = resourceConfig.getSimple("idmap uid").getStringValue(); String idmapgid = resourceConfig.getSimple("idmap gid").getStringValue(); String shell = resourceConfig.getSimple("template shell").getStringValue(); if (realm == null || controller == null || username == null || password == null || workgroup == null) { result.setSimpleResult("Missing required connection parameters"); return result; } StringBuilder authArgs = new StringBuilder(); StringBuilder netArgs = new StringBuilder(); // AuthConfig arguments...ugly and would be a lot prettier using python authArgs.append("--smbservers=" + controller); authArgs.append(SPACE + "--smbrealm=" + realm); authArgs.append(SPACE + "--enablewinbind --smbsecurity=ads"); if (idmapuid != null) { authArgs.append(SPACE + "--smbidmapuid=" + idmapuid); } if (idmapgid != null) { authArgs.append(SPACE + "--smbidmapgid=" + idmapgid); } if (shell != null) { authArgs.append(SPACE + "--winbindtemplateshell=" + shell); } authArgs.append(SPACE + "--update"); // Net join arguments netArgs.append("join"); netArgs.append(SPACE + "-w " + workgroup); netArgs.append(SPACE + "-S " + controller); netArgs.append(SPACE + "-U " + username + "%" + password); ProcessExecutionResults authResults = execute(AUTHCONFIG_PATH, authArgs.toString()); ProcessExecutionResults netResults = execute(NET_PATH, netArgs.toString()); String results = authResults.getCapturedOutput() + netResults.getCapturedOutput(); result.setSimpleResult(results); return result; } private ProcessExecutionResults execute(String path, String args) throws InvalidPluginConfigurationException { ProcessExecution processExecution = new ProcessExecution(path); SystemInfo sysInfo = this.resourceContext.getSystemInformation(); if (args != null) { processExecution.setArguments(args.split(" ")); } processExecution.setCaptureOutput(true); processExecution.setWaitForCompletion(1000L); processExecution.setKillOnTimeout(true); ProcessExecutionResults results = sysInfo.executeProcess(processExecution); return results; } }