// 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.outofbandmanagement.driver.ipmitool; import com.cloud.utils.StringUtils; import com.cloud.utils.exception.CloudRuntimeException; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; import org.apache.cloudstack.utils.process.ProcessResult; import org.apache.cloudstack.utils.process.ProcessRunner; import org.apache.log4j.Logger; import org.joda.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; public final class IpmitoolWrapper { public static final Logger LOG = Logger.getLogger(IpmitoolWrapper.class); private final ProcessRunner RUNNER; public IpmitoolWrapper(ExecutorService executor) { this.RUNNER = new ProcessRunner(executor); } public String parsePowerCommand(OutOfBandManagement.PowerOperation operation) { if (operation == null) { throw new IllegalStateException("Invalid power operation requested"); } switch (operation) { case ON: case OFF: case CYCLE: case RESET: case SOFT: case STATUS: break; default: throw new IllegalStateException("Invalid power operation requested"); } return operation.toString().toLowerCase(); } public OutOfBandManagement.PowerState parsePowerState(final String standardOutput) { if (Strings.isNullOrEmpty(standardOutput)) { return OutOfBandManagement.PowerState.Unknown; } if (standardOutput.equals("Chassis Power is on")) { return OutOfBandManagement.PowerState.On; } else if (standardOutput.equals("Chassis Power is off")) { return OutOfBandManagement.PowerState.Off; } return OutOfBandManagement.PowerState.Unknown; } public List<String> getIpmiToolCommandArgs(final String ipmiToolPath, final String ipmiInterface, final String retries, final ImmutableMap<OutOfBandManagement.Option, String> options, String... commands) { final ImmutableList.Builder<String> ipmiToolCommands = ImmutableList.<String>builder() .add(ipmiToolPath) .add("-I") .add(ipmiInterface) .add("-R") .add(retries) .add("-v"); if (options != null) { for (ImmutableMap.Entry<OutOfBandManagement.Option, String> option : options.entrySet()) { switch (option.getKey()) { case ADDRESS: ipmiToolCommands.add("-H"); break; case PORT: ipmiToolCommands.add("-p"); break; case USERNAME: ipmiToolCommands.add("-U"); break; case PASSWORD: ipmiToolCommands.add("-P"); break; default: continue; } ipmiToolCommands.add(option.getValue()); } } for (String command : commands) { ipmiToolCommands.add(command); } return ipmiToolCommands.build(); } public String findIpmiUser(final String usersList, final String username) { /** * Expected usersList string contains legends on first line and users on rest * ID Name Callin Link Auth IPMI Msg Channel Priv Limit * 1 admin true true true ADMINISTRATOR */ // Assuming user 'ID' index on 1st position int idIndex = 0; // Assuming user 'Name' index on 2nd position int usernameIndex = 1; final String[] lines = usersList.split("\\r?\\n"); if (lines.length < 2) { throw new CloudRuntimeException("Error parsing user ID from ipmi user listing"); } // Find user and name indexes from the 1st line if not on default position final String[] legends = lines[0].split(" +"); for (int idx = 0; idx < legends.length; idx++) { if (legends[idx].equals("ID")) { idIndex = idx; } if (legends[idx].equals("Name")) { usernameIndex = idx; } } // Find user 'ID' based on provided username and ID/Name positions String userId = null; for (int idx = 1; idx < lines.length; idx++) { final String[] words = lines[idx].split(" +"); if (usernameIndex < words.length && idIndex < words.length) { if (words[usernameIndex].equals(username)) { userId = words[idIndex]; } } } return userId; } public OutOfBandManagementDriverResponse executeCommands(final List<String> commands) { return executeCommands(commands, ProcessRunner.DEFAULT_MAX_TIMEOUT); } public OutOfBandManagementDriverResponse executeCommands(final List<String> commands, final Duration timeOut) { final ProcessResult result = RUNNER.executeCommands(commands, timeOut); if (LOG.isTraceEnabled()) { List<String> cleanedCommands = new ArrayList<String>(); int maskNextCommand = 0; for (String command : commands) { if (maskNextCommand > 0) { cleanedCommands.add("**** "); maskNextCommand--; continue; } if (command.equalsIgnoreCase("-P")) { maskNextCommand = 1; } else if (command.toLowerCase().endsWith("password")) { maskNextCommand = 2; } cleanedCommands.add(command); } LOG.trace("Executed ipmitool process with commands: " + StringUtils.join(cleanedCommands, ", ") + "\nIpmitool execution standard output: " + result.getStdOutput() + "\nIpmitool execution error output: " + result.getStdError()); } return new OutOfBandManagementDriverResponse(result.getStdOutput(), result.getStdError(), result.isSuccess()); } }