/** * Copyright 2013-2015 Seagate Technology LLC. * * This Source Code Form is subject to the terms of the Mozilla * Public License, v. 2.0. If a copy of the MPL was not * distributed with this file, You can obtain one at * https://mozilla.org/MP:/2.0/. * * This program is distributed in the hope that it will be useful, * but is provided AS-IS, WITHOUT ANY WARRANTY; including without * the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or * FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public * License for more details. * * See www.openkinetic.org for more project information */ package com.seagate.kinetic.admin.impl; import java.util.List; import kinetic.admin.ACL; import kinetic.admin.Device; import kinetic.admin.Domain; import kinetic.admin.KineticAdminClient; import kinetic.admin.KineticLog; import kinetic.admin.KineticLogType; import kinetic.client.ClientConfiguration; import kinetic.client.KineticException; import com.google.protobuf.ByteString; import com.seagate.kinetic.client.internal.MessageFactory; import com.seagate.kinetic.client.internal.p2p.DefaultKineticP2pClient; import com.seagate.kinetic.common.lib.HMACAlgorithmUtil; import com.seagate.kinetic.common.lib.KineticMessage; import com.seagate.kinetic.proto.Kinetic.Command; import com.seagate.kinetic.proto.Kinetic.Command.GetLog; import com.seagate.kinetic.proto.Kinetic.Command.GetLog.Type; import com.seagate.kinetic.proto.Kinetic.Command.Header; import com.seagate.kinetic.proto.Kinetic.Command.MessageType; import com.seagate.kinetic.proto.Kinetic.Command.PinOperation.PinOpType; import com.seagate.kinetic.proto.Kinetic.Command.Priority; import com.seagate.kinetic.proto.Kinetic.Command.Range; import com.seagate.kinetic.proto.Kinetic.Command.Security; import com.seagate.kinetic.proto.Kinetic.Command.Security.ACL.HMACAlgorithm; import com.seagate.kinetic.proto.Kinetic.Command.Setup; import com.seagate.kinetic.proto.Kinetic.Command.Status; import com.seagate.kinetic.proto.Kinetic.Command.Status.StatusCode; import com.seagate.kinetic.proto.Kinetic.Message; import com.seagate.kinetic.proto.Kinetic.Message.AuthType; import com.seagate.kinetic.proto.Kinetic.Message.PINauth; /** * This class provides administrative API for a kinetic administrator to * configure a kinetic server/service/drive. * */ public class DefaultAdminClient extends DefaultKineticP2pClient implements KineticAdminClient { /** * Construct a new instance of kinetic admin client. * * @param config * client configuration, such as server host/port. * @throws KineticException * if any internal error occurred. */ public DefaultAdminClient(ClientConfiguration config) throws KineticException { super (config); } /** * Configure security policies for a kinetic drive. * * @param request * the request message contains ACL list. * @return respond message from the service * @throws KineticException * if any internal error occurred. */ public KineticMessage configureSecurityPolicy(KineticMessage km) throws KineticException { Command.Builder commandBuilder = (Command.Builder) km.getCommand(); // set request message type commandBuilder.getHeaderBuilder() .setMessageType(MessageType.SECURITY); // send security request to server. KineticMessage respond = request(km); // return respond message. return respond; } /** * Configure setup policies for a kinetic drive. * * @param request * the request message contains setup content. * @return respond message. * @throws KineticException * if any internal error occurred. */ public KineticMessage configureSetupPolicy(KineticMessage km) throws KineticException { Command.Builder commandBuilder = (Command.Builder) km.getCommand(); commandBuilder.getHeaderBuilder() .setMessageType(MessageType.SETUP); KineticMessage response = request(km); return response; } /** * Configure getLog policies for a kinetic drive. * * @param request * the request message contains getLog content. * @return respond message. * @throws KineticException * if any internal error occurred. */ public KineticMessage getLog(KineticMessage km) throws KineticException { Command.Builder request = (Command.Builder) km.getCommand(); request.getHeaderBuilder() .setMessageType(MessageType.GETLOG); KineticMessage response = request(km); return response; } @Override public void instantErase(byte[] pin) throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Message.Builder mb = (Message.Builder) km.getMessage(); mb.setAuthType(AuthType.PINAUTH); if (pin != null) { mb.setPinAuth(PINauth.newBuilder().setPin(ByteString.copyFrom(pin))); } Command.Builder commandBuilder = (Command.Builder) km.getCommand(); commandBuilder.getHeaderBuilder() .setMessageType(MessageType.PINOP); commandBuilder.getBodyBuilder().getPinOpBuilder().setPinOpType(PinOpType.ERASE_PINOP); KineticMessage response = request(km); if (response.getCommand().getStatus().getCode() != StatusCode.SUCCESS) { KineticException ke = new KineticException ("erase db failed."); ke.setRequestMessage(km); ke.setResponseMessage(response); throw ke; } } private void validate(List<ACL> acls) throws KineticException { if (null == acls || acls.isEmpty() || 0 == acls.size()) { throw new KineticException( "Paramter Exception: acl list is null or empty!"); } for (ACL acl : acls) { if (null == acl.getKey()) { throw new KineticException( "Paramter Exception: key can't be null."); } if (0 > acl.getUserId()) { throw new KineticException( "Paramter Exception: userid can't be less than 0."); } if (null != acl.getAlgorithm()) { if (!HMACAlgorithmUtil.isSupported(acl.getAlgorithm())) { throw new KineticException( "Parameter Exception: this algorithm is not supported."); } } if (null == acl.getDomains() || acl.getDomains().isEmpty()) { throw new KineticException( "Paramter Exception: scope can't be null or empty."); } for (Domain domainInfo : acl.getDomains()) { if (domainInfo.getOffset() < 0) { throw new KineticException( "Paramter Exception: offset can't be less than 0."); } if (null == domainInfo.getRoles() || domainInfo.getRoles().isEmpty()) { throw new KineticException( "Paramter Exception: role list can't be null or empty."); } } } } public void setSecurity(List<ACL> acls, byte[] oldLockPin, byte[] newLockPin, byte[] oldErasePin, byte[] newErasePin) throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); Security.Builder security = commandBuilder .getBodyBuilder().getSecurityBuilder(); validate(acls); for (ACL aclInfo : acls) { com.seagate.kinetic.proto.Kinetic.Command.Security.ACL.Builder acl = com.seagate.kinetic.proto.Kinetic.Command.Security.ACL .newBuilder(); if (aclInfo.getAlgorithm() != null) { acl.setHmacAlgorithm(HMACAlgorithm.valueOf(aclInfo .getAlgorithm().toString())); } else { acl.setHmacAlgorithm(HMACAlgorithm.HmacSHA1); } acl.setIdentity(aclInfo.getUserId()); acl.setKey(ByteString.copyFromUtf8(aclInfo.getKey())); for (Domain domainInfo : aclInfo.getDomains()) { com.seagate.kinetic.proto.Kinetic.Command.Security.ACL.Scope.Builder scope = com.seagate.kinetic.proto.Kinetic.Command.Security.ACL.Scope .newBuilder(); scope.setOffset(domainInfo.getOffset()); scope.setValue(ByteString.copyFromUtf8(domainInfo.getValue())); for (kinetic.admin.Role role : domainInfo.getRoles()) { scope.addPermission(com.seagate.kinetic.proto.Kinetic.Command.Security.ACL.Permission .valueOf(role.toString())); } acl.addScope(scope.build()); } // set old lock pin if (oldLockPin != null) { security.setOldLockPIN(ByteString.copyFrom(oldLockPin)); } // set new lock pin if (newLockPin != null) { security.setNewLockPIN(ByteString.copyFrom(newLockPin)); } // set old erase pin if (oldErasePin != null) { security.setOldErasePIN (ByteString.copyFrom(oldErasePin)); } // set new erase pin if (newErasePin != null) { security.setNewErasePIN (ByteString.copyFrom(newErasePin)); } security.addAcl(acl.build()); } KineticMessage response = configureSecurityPolicy(km); if (response.getCommand().getHeader().getMessageType() != MessageType.SECURITY_RESPONSE) { throw new KineticException("received wrong message type."); } if (response.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus() .getStatusMessage()); } if (response.getCommand().getStatus().getCode() == Status.StatusCode.NO_SUCH_HMAC_ALGORITHM) { throw new KineticException("Hmac algorithm Exception: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus() .getStatusMessage()); } if (response.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus() .getStatusMessage()); } } @Override public void setClusterVersion (long newClusterVersion) throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); Setup.Builder setup = commandBuilder.getBodyBuilder() .getSetupBuilder(); if (0 > newClusterVersion) { throw new KineticException( "Parameter invalid: new cluster version less than 0."); } setup.setNewClusterVersion(newClusterVersion); KineticMessage kmresp = configureSetupPolicy(km); if (kmresp.getCommand().getHeader().getMessageType() != MessageType.SETUP_RESPONSE) { throw new KineticException("received wrong message type."); } if (kmresp.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } if (kmresp.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } } @Override public KineticLog getLog() throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); GetLog.Builder getLog = commandBuilder.getBodyBuilder() .getGetLogBuilder(); getLog.addTypes(Type.CAPACITIES); getLog.addTypes(Type.CONFIGURATION); getLog.addTypes(Type.MESSAGES); getLog.addTypes(Type.STATISTICS); getLog.addTypes(Type.TEMPERATURES); getLog.addTypes(Type.UTILIZATIONS); getLog.addTypes(Type.LIMITS); KineticMessage kmresp = getLog(km); if (kmresp.getCommand().getHeader().getMessageType() != MessageType.GETLOG_RESPONSE) { throw new KineticException("received wrong message type."); } if (kmresp.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } if (kmresp.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } KineticLog kineticLOG = new DefaultKineticLog(kmresp); return kineticLOG; } /** * {@inheritDoc} */ @Override public KineticLog getLog(List<KineticLogType> listOfLogType) throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); GetLog.Builder getLog = commandBuilder.getBodyBuilder() .getGetLogBuilder(); for (KineticLogType getLogType : listOfLogType) { switch (getLogType) { case CAPACITIES: getLog.addTypes(Type.CAPACITIES); break; case TEMPERATURES: getLog.addTypes(Type.TEMPERATURES); break; case UTILIZATIONS: getLog.addTypes(Type.UTILIZATIONS); break; case CONFIGURATION: getLog.addTypes(Type.CONFIGURATION); break; case MESSAGES: getLog.addTypes(Type.MESSAGES); break; case STATISTICS: getLog.addTypes(Type.STATISTICS); break; case LIMITS: getLog.addTypes(Type.LIMITS); break; case DEVICE: throw new java.lang.UnsupportedOperationException( "Please use #getVendorSpecificDeviceLog() to get vendor specific log."); default: ; } } KineticMessage kmresp = getLog(km); checkGetLogResponse(kmresp); KineticLog kineticLog = new DefaultKineticLog(kmresp); return kineticLog; } /** * {@inheritDoc} */ @Override public void firmwareDownload(byte[] bytes) throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); Setup.Builder setup = commandBuilder.getBodyBuilder() .getSetupBuilder(); setup.setFirmwareDownload(true); if (null != bytes && bytes.length > 0) { // request.setValue(ByteString.copyFrom(bytes)); km.setValue(bytes); } commandBuilder.getHeaderBuilder() .setMessageType(MessageType.SETUP); KineticMessage kmresp = request(km); if (kmresp.getCommand().getHeader().getMessageType() != MessageType.SETUP_RESPONSE) { throw new KineticException("received wrong message type."); } if (kmresp.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } if (kmresp.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } } @Override public Device getVendorSpecificDeviceLog(byte[] name) throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); GetLog.Builder getLog = commandBuilder.getBodyBuilder() .getGetLogBuilder(); // add DEVICE type getLog.addTypes(Type.DEVICE); // set vendor specific log name getLog.getDeviceBuilder().setName(ByteString.copyFrom(name)); // send getLog/DEVICE message KineticMessage kmresp = getLog(km); // sanity check response checkGetLogResponse(kmresp); // get vendor specific getLog/DEVICE name/value byte[] value = kmresp.getValue(); Device device = new Device(); device.setName (name); device.setValue(value); return device; } /** * Sanity check getLog response message. * * @param response * @throws KineticException */ private static void checkGetLogResponse (KineticMessage response) throws KineticException { if (response.getCommand().getHeader().getMessageType() != MessageType.GETLOG_RESPONSE) { throw new KineticException("received wrong message type."); } if (response.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus().getStatusMessage()); } if (response.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus().getStatusMessage()); } } @Override public void secureErase(byte[] pin) throws KineticException { this.instantErase(pin); } @Override public void lockDevice(byte[] pin) throws KineticException { if (pin == null || pin.length == 0) { throw new KineticException ("Pin mut not be null or empty"); } KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Message.Builder mb = (Message.Builder) km.getMessage(); mb.setAuthType(AuthType.PINAUTH); mb.setPinAuth(PINauth.newBuilder().setPin(ByteString.copyFrom(pin))); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); commandBuilder.getHeaderBuilder() .setMessageType(MessageType.PINOP); commandBuilder.getBodyBuilder().getPinOpBuilder().setPinOpType(PinOpType.LOCK_PINOP); KineticMessage response = request(km); if (response.getCommand().getStatus().getCode() != StatusCode.SUCCESS) { KineticException ke = new KineticException ("Pin op lock device failed."); ke.setRequestMessage(km); ke.setResponseMessage(response); throw ke; } } @Override public void unLockDevice(byte[] pin) throws KineticException { if (pin == null || pin.length == 0) { throw new KineticException ("Pin mut not be null or empty"); } KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Message.Builder mb = (Message.Builder) km.getMessage(); mb.setAuthType(AuthType.PINAUTH); mb.setPinAuth(PINauth.newBuilder().setPin(ByteString.copyFrom(pin))); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); commandBuilder.getHeaderBuilder() .setMessageType(MessageType.PINOP); commandBuilder.getBodyBuilder().getPinOpBuilder().setPinOpType(PinOpType.UNLOCK_PINOP); KineticMessage response = request(km); if (response.getCommand().getStatus().getCode() != StatusCode.SUCCESS) { KineticException ke = new KineticException ("Pin op lock device failed."); ke.setRequestMessage(km); ke.setResponseMessage(response); throw ke; } } @Override public void setAcl(List<ACL> acls) throws KineticException { this.setSecurity(acls, null, null, null, null); } @Override public void setLockPin(byte[] oldLockPin, byte[] newLockPin) throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); Security.Builder security = commandBuilder.getBodyBuilder() .getSecurityBuilder(); // set old lock pin if (oldLockPin != null) { security.setOldLockPIN(ByteString.copyFrom(oldLockPin)); } // set new lock pin if (newLockPin != null) { security.setNewLockPIN(ByteString.copyFrom(newLockPin)); } KineticMessage response = configureSecurityPolicy(km); if (response.getCommand().getHeader().getMessageType() != MessageType.SECURITY_RESPONSE) { throw new KineticException("received wrong message type."); } if (response.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus().getStatusMessage()); } if (response.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus().getStatusMessage()); } } @Override public void setErasePin(byte[] oldErasePin, byte[] newErasePin) throws KineticException { KineticMessage km = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) km.getCommand(); Security.Builder security = commandBuilder.getBodyBuilder() .getSecurityBuilder(); // set old erase pin if (oldErasePin != null) { security.setOldErasePIN (ByteString.copyFrom(oldErasePin)); } // set new erase pin if (newErasePin != null) { security.setNewErasePIN (ByteString.copyFrom(newErasePin)); } KineticMessage response = configureSecurityPolicy(km); if (response.getCommand().getHeader().getMessageType() != MessageType.SECURITY_RESPONSE) { throw new KineticException("received wrong message type."); } if (response.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus().getStatusMessage()); } if (response.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + response.getCommand().getStatus().getCode() + ": " + response.getCommand().getStatus().getStatusMessage()); } } @Override public KineticMessage mediaScan(Range range, Priority priority) throws KineticException { // create request message KineticMessage kmreq = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) kmreq.getCommand(); Header.Builder header = commandBuilder.getHeaderBuilder(); // set message type header.setMessageType(MessageType.MEDIASCAN); // set priority header.setPriority(priority); // set range commandBuilder.getBodyBuilder().setRange(range); KineticMessage kmresp = request (kmreq); if (kmresp.getCommand().getHeader().getMessageType() != MessageType.MEDIASCAN_RESPONSE) { throw new KineticException("received wrong message type."); } if (kmresp.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } if (kmresp.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } return kmresp; } @Override public KineticMessage mediaOptimize(Range range, Priority priority) throws KineticException { // create request message KineticMessage kmreq = MessageFactory.createKineticMessageWithBuilder(); Command.Builder commandBuilder = (Command.Builder) kmreq.getCommand(); Header.Builder header = commandBuilder.getHeaderBuilder(); // set message type header.setMessageType(MessageType.MEDIAOPTIMIZE); // set priority header.setPriority(priority); // set range commandBuilder.getBodyBuilder().setRange(range); KineticMessage kmresp = request (kmreq); if (kmresp.getCommand().getHeader().getMessageType() != MessageType.MEDIAOPTIMIZE_RESPONSE) { throw new KineticException("received wrong message type."); } if (kmresp.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) { throw new KineticException("Authorized Exception: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } if (kmresp.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) { throw new KineticException("Unknown Error: " + kmresp.getCommand().getStatus().getCode() + ": " + kmresp.getCommand().getStatus().getStatusMessage()); } return kmresp; } /** * @deprecated */ @Deprecated @Override public void firmwareDownload(byte[] pin, byte[] bytes) throws KineticException { this.firmwareDownload(bytes); } }