/*
* Copyright (c) 2011 by Paul Seiferth, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.common.libxtreemfs;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.xtreemfs.common.HeartbeatThread;
import org.xtreemfs.common.KeyValuePairs;
import org.xtreemfs.common.libxtreemfs.RPCCaller.CallGenerator;
import org.xtreemfs.common.libxtreemfs.exceptions.AddressToUUIDNotFoundException;
import org.xtreemfs.common.libxtreemfs.exceptions.PosixErrorException;
import org.xtreemfs.common.libxtreemfs.exceptions.VolumeNotFoundException;
import org.xtreemfs.common.uuids.ServiceUUID;
import org.xtreemfs.common.uuids.UnknownUUIDException;
import org.xtreemfs.dir.DIRClient;
import org.xtreemfs.foundation.SSLOptions;
import org.xtreemfs.foundation.TimeSync;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.pbrpc.client.RPCAuthentication;
import org.xtreemfs.foundation.pbrpc.client.RPCNIOSocketClient;
import org.xtreemfs.foundation.pbrpc.client.RPCResponse;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.AuthPassword;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.AuthType;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.UserCredentials;
import org.xtreemfs.pbrpc.generatedinterfaces.Common.emptyRequest;
import org.xtreemfs.pbrpc.generatedinterfaces.Common.emptyResponse;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.Service;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.ServiceDataMap;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.ServiceSet;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.ServiceStatus;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.ServiceType;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.serviceGetByNameRequest;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.serviceGetByTypeRequest;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.serviceGetByUUIDRequest;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.serviceRegisterRequest;
import org.xtreemfs.pbrpc.generatedinterfaces.DIR.serviceRegisterResponse;
import org.xtreemfs.pbrpc.generatedinterfaces.DIRServiceClient;
import org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes;
import org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.AccessControlPolicyType;
import org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.KeyValuePair;
import org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.SERVICES;
import org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.StripingPolicy;
import org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.StripingPolicyType;
import org.xtreemfs.pbrpc.generatedinterfaces.MRC.Volumes;
import org.xtreemfs.pbrpc.generatedinterfaces.MRCServiceClient;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.xtreemfs_cleanup_get_resultsResponse;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.xtreemfs_cleanup_is_runningResponse;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.xtreemfs_cleanup_startRequest;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.xtreemfs_cleanup_statusResponse;
import org.xtreemfs.pbrpc.generatedinterfaces.OSDServiceClient;
/**
* Standard implementation of the client. Used only internally.
*/
public class ClientImplementation implements UUIDResolver, Client, AdminClient {
/**
* Contains all addresses of the DIR Service.
*/
private UUIDIterator dirServiceAddresses = null;
/**
* Auth of type AUTH_NONE which is required for most operations which do not check the authentication data
* (except Create, Delete, ListVolume(s)).
*/
private Auth authBogus = null;
/** The auth_type of this object will always be set to AUTH_NONE. */
// TODO: change this when the DIR service supports real auth.
private Auth dirServiceAuth;
/** These credentials will be used for messages to the DIR service. */
private UserCredentials dirServiceUserCredentials = null;
private SSLOptions dirServiceSSLOptions = null;
/** Options class which contains the log_level string and logfile path. */
private Options options = null;
private ConcurrentLinkedQueue<Volume> listOpenVolumes = null;
private org.xtreemfs.common.uuids.UUIDResolver uuidResolver = null;
/**
* A DIRServiceClient is a wrapper for an RPC Client.
*/
private DIRServiceClient dirServiceClient = null;
/**
* An OSDServiceClient is a wrapper for an RPC Client.
*/
private OSDServiceClient osdServiceClient = null;
/**
* The RPC Client processes requests from a queue and executes callbacks in its thread.
*/
private RPCNIOSocketClient networkClient = null;
/**
* Random, non-persistent UUID to distinguish locks of different clients.
*/
private String clientUUID = null;
/**
* Array with all DIR addresses.
*/
private String[] dirAddresses = null;
/**
* If true, all threads (inclusive volumes opened by this client) are daemons.
*/
private boolean startThreadsAsDaemons = false;
protected ClientImplementation(String[] dirAddresses, UserCredentials userCredentials,
SSLOptions sslOptions, Options options) {
this.dirServiceUserCredentials = userCredentials;
this.dirServiceSSLOptions = sslOptions;
this.options = options;
this.dirAddresses = dirAddresses;
this.dirServiceAddresses = new UUIDIterator();
for (String address : dirAddresses) {
this.dirServiceAddresses.addUUID(address);
}
// Set bogus auth object
this.authBogus = Auth.newBuilder().setAuthType(AuthType.AUTH_NONE).build();
// Currently no AUTH is required to access the DIR
this.dirServiceAuth = Auth.newBuilder().setAuthType(AuthType.AUTH_NONE).build();
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "Created a new libxtreemfs Client "
+ "object (version %s)", options.getVersion());
}
this.listOpenVolumes = new ConcurrentLinkedQueue<Volume>();
}
@Override
public void start() throws Exception {
start(false);
}
@Override
public void start(boolean startThreadsAsDaemons) throws Exception {
this.startThreadsAsDaemons = startThreadsAsDaemons;
this.networkClient = new RPCNIOSocketClient(this.dirServiceSSLOptions,
this.options.getRequestTimeout_s() * 1000, this.options.getLingerTimeout_s() * 1000, "Client", startThreadsAsDaemons);
this.networkClient.start();
this.networkClient.waitForStartup();
TimeSync tsInstance = TimeSync.initializeLocal(50);
tsInstance.waitForStartup();
this.dirServiceClient = new DIRServiceClient(this.networkClient, null);
osdServiceClient = new OSDServiceClient(networkClient, null);
this.clientUUID = Helper.generateVersion4UUID();
assert (this.clientUUID != null && this.clientUUID != "");
// Create nonSingleton uuidResolver to resolve UUIDs.
InetSocketAddress[] isas = new InetSocketAddress[dirAddresses.length];
for (int i = 0; i < dirAddresses.length; i++) {
isas[i] = Helper.stringToInetSocketAddress(dirAddresses[i],
GlobalTypes.PORTS.DIR_PBRPC_PORT_DEFAULT.getNumber());
}
DIRClient dirClient = new DIRClient(this.dirServiceClient, isas, this.options.getMaxTries(),
this.options.getRetryDelay_s() * 1000);
this.uuidResolver = org.xtreemfs.common.uuids.UUIDResolver.startNonSingelton(dirClient, 3600, 1000);
}
@Override
public synchronized void shutdown() {
for (Volume volume : this.listOpenVolumes) {
volume.close();
}
if (this.dirServiceClient != null) {
try {
this.networkClient.shutdown();
this.networkClient.waitForShutdown();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
protected void closeVolume(Volume volume) {
boolean removed = this.listOpenVolumes.remove(volume);
assert (removed);
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#openVolume(java.lang.String,
* org.xtreemfs.foundation.SSLOptions, org.xtreemfs.common.libxtreemfs.Options)
*/
@Override
public AdminVolume openVolume(String volumeName, SSLOptions sslOptions, Options options)
throws AddressToUUIDNotFoundException, VolumeNotFoundException, IOException {
UUIDIterator mrcUuidIterator = new UUIDIterator();
volumeNameToMRCUUID(volumeName, mrcUuidIterator);
VolumeImplementation volume = new VolumeImplementation(this, this.clientUUID, mrcUuidIterator,
volumeName, sslOptions, options);
volume.start(startThreadsAsDaemons);
this.listOpenVolumes.add(volume);
return volume;
}
public void createVolume(String mrcAddress, Auth auth, UserCredentials userCredentials, String volumeName)
throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
List<KeyValuePair> volumeAttributes = new ArrayList<KeyValuePair>();
createVolume(mrcAddress, auth, userCredentials, volumeName, 511, "", "",
AccessControlPolicyType.ACCESS_CONTROL_POLICY_POSIX,
StripingPolicyType.STRIPING_POLICY_RAID0, 128, 1, volumeAttributes);
};
public void createVolume(List<String> mrcAddresses, Auth auth, UserCredentials userCredentials,
String volumeName) throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
List<KeyValuePair> volumeAttributes = new ArrayList<KeyValuePair>();
createVolume(mrcAddresses, auth, userCredentials, volumeName, 511, "", "",
AccessControlPolicyType.ACCESS_CONTROL_POLICY_POSIX,
StripingPolicyType.STRIPING_POLICY_RAID0, 128, 1, volumeAttributes);
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#createVolume(java.lang.String,
* org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth, org.xtreemfs.common.auth.UserCredentials,
* java.lang.String, int, java.lang.String, java.lang.String, org.xtreemfs.pbrpc.generatedinterfaces
* .GlobalTypes.AccessControlPolicyType,
* org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.StripingPolicyType, int, int, java.util.List)
*/
@Override
public void createVolume(String mrcAddress, Auth auth, UserCredentials userCredentials,
String volumeName, int mode, String ownerUsername, String ownerGroupname,
AccessControlPolicyType accessPolicyType, StripingPolicyType defaultStripingPolicyType,
int defaultStripeSize, int defaultStripeWidth, List<KeyValuePair> volumeAttributes)
throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
UUIDIterator iteratorWithAddresses = new UUIDIterator();
iteratorWithAddresses.addUUID(mrcAddress);
createVolume(iteratorWithAddresses, auth, userCredentials, volumeName, mode, ownerUsername,
ownerGroupname, accessPolicyType, defaultStripingPolicyType, defaultStripeSize,
defaultStripeWidth, volumeAttributes);
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#createVolume(java.lang.String,
* org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth, org.xtreemfs.common.auth.UserCredentials,
* java.lang.String, int, java.lang.String, java.lang.String, org.xtreemfs.pbrpc.generatedinterfaces
* .GlobalTypes.AccessControlPolicyType,
* org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.StripingPolicyType, int, int, java.util.List)
*/
@Override
public void createVolume(Auth auth, UserCredentials userCredentials, String volumeName, int mode,
String ownerUsername, String ownerGroupname, AccessControlPolicyType accessPolicyType,
StripingPolicyType defaultStripingPolicyType, int defaultStripeSize, int defaultStripeWidth,
List<KeyValuePair> volumeAttributes) throws IOException, PosixErrorException,
AddressToUUIDNotFoundException {
// access the list of MRCs
ServiceSet mrcs = RPCCaller.<String, ServiceSet> syncCall(SERVICES.DIR,
this.dirServiceUserCredentials, this.dirServiceAuth, this.options, this,
this.dirServiceAddresses, true, null, new CallGenerator<String, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, String input) throws IOException {
return ClientImplementation.this.dirServiceClient.xtreemfs_service_get_by_type(
server, authHeader, userCreds, ServiceType.SERVICE_TYPE_MRC);
}
});
if (mrcs.getServicesCount() == 0) {
throw new IOException("no MRC available for volume creation");
}
List<String> mrcAddresses = new ArrayList<String>();
for (Service uuid : mrcs.getServicesList()) {
mrcAddresses.add(uuidToAddress(uuid.getUuid()));
}
createVolume(mrcAddresses, auth, userCredentials, volumeName, mode, ownerUsername, ownerGroupname,
accessPolicyType, defaultStripingPolicyType, defaultStripeSize, defaultStripeWidth,
volumeAttributes);
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#createVolume(java.util.List,
* org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth, org.xtreemfs.common.auth.UserCredentials,
* java.lang.String, int, java.lang.String, java.lang.String, org.xtreemfs.pbrpc.generatedinterfaces
* .GlobalTypes.AccessControlPolicyType,
* org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.StripingPolicyType, int, int, java.util.List)
*/
@Override
public void createVolume(List<String> mrcAddresses, Auth auth, UserCredentials userCredentials,
String volumeName, int mode, String ownerUsername, String ownerGroupname,
AccessControlPolicyType accessPolicyType, StripingPolicyType defaultStripingPolicyType,
int defaultStripeSize, int defaultStripeWidth, List<KeyValuePair> volumeAttributes)
throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
UUIDIterator iteratorWithAddresses = new UUIDIterator();
iteratorWithAddresses.addUUIDs(mrcAddresses);
createVolume(iteratorWithAddresses, auth, userCredentials, volumeName, mode, ownerUsername,
ownerGroupname, accessPolicyType, defaultStripingPolicyType, defaultStripeSize,
defaultStripeWidth, volumeAttributes);
}
private void createVolume(UUIDIterator mrcAddresses, Auth auth, UserCredentials userCredentials,
String volumeName, int mode, String ownerUsername, String ownerGroupname,
AccessControlPolicyType accessPolicyType, StripingPolicyType defaultStripingPolicyType,
int defaultStripeSize, int defaultStripeWidth, List<KeyValuePair> volumeAttributes)
throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
final MRCServiceClient mrcClient = new MRCServiceClient(this.networkClient, null);
StripingPolicy sp = StripingPolicy.newBuilder().setType(defaultStripingPolicyType)
.setStripeSize(defaultStripeSize).setWidth(defaultStripeWidth).build();
org.xtreemfs.pbrpc.generatedinterfaces.MRC.Volume volume = org.xtreemfs.pbrpc.generatedinterfaces.MRC.Volume
.newBuilder().setName(volumeName).setMode(mode).setOwnerUserId(ownerUsername)
.setOwnerGroupId(ownerGroupname).setAccessControlPolicy(accessPolicyType)
.setDefaultStripingPolicy(sp).addAllAttrs(volumeAttributes).setId("").build();
RPCCaller.<org.xtreemfs.pbrpc.generatedinterfaces.MRC.Volume, emptyResponse> syncCall(SERVICES.MRC,
userCredentials, auth, this.options, this, mrcAddresses, true, volume,
new CallGenerator<org.xtreemfs.pbrpc.generatedinterfaces.MRC.Volume, emptyResponse>() {
@SuppressWarnings("unchecked")
@Override
public RPCResponse<emptyResponse> executeCall(InetSocketAddress server, Auth auth,
UserCredentials userCreds, org.xtreemfs.pbrpc.generatedinterfaces.MRC.Volume input)
throws IOException {
return mrcClient.xtreemfs_mkvol(server, auth, userCreds, input);
};
});
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#deleteVolume(java.lang.String,
* org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth, org.xtreemfs.common.auth.UserCredentials,
* java.lang.String)
*/
@Override
public void deleteVolume(Auth auth, UserCredentials userCredentials, String volumeName)
throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
ServiceSet s = RPCCaller.<String, ServiceSet> syncCall(SERVICES.DIR, this.dirServiceUserCredentials,
this.dirServiceAuth, this.options, this, this.dirServiceAddresses, true, volumeName,
new CallGenerator<String, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, String volumeName) throws IOException {
return ClientImplementation.this.dirServiceClient.xtreemfs_service_get_by_name(
server, authHeader, userCreds, volumeName);
}
});
if (s == null || s.getServicesCount() == 0) {
throw new IOException("volume '" + volumeName + "' does not exist");
}
if (s != null) {
final Service vol = s.getServices(0);
final String mrcAddress = uuidToAddress(KeyValuePairs
.getValue(vol.getData().getDataList(), "mrc"));
deleteVolume(mrcAddress, auth, userCredentials, volumeName);
}
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#deleteVolume(java.lang.String,
* org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth, org.xtreemfs.common.auth.UserCredentials,
* java.lang.String)
*/
@Override
public void deleteVolume(String mrcAddress, Auth auth, UserCredentials userCredentials, String volumeName)
throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
UUIDIterator iteratorWithAddresses = new UUIDIterator();
iteratorWithAddresses.addUUID(mrcAddress);
deleteVolume(iteratorWithAddresses, auth, userCredentials, volumeName);
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#deleteVolume(java.util.List,
* org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth, org.xtreemfs.common.auth.UserCredentials,
* java.lang.String)
*/
@Override
public void deleteVolume(List<String> mrcAddresses, Auth auth, UserCredentials userCredentials,
String volumeName) throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
UUIDIterator iteratorWithAddresses = new UUIDIterator();
iteratorWithAddresses.addUUIDs(mrcAddresses);
deleteVolume(iteratorWithAddresses, auth, userCredentials, volumeName);
}
private void deleteVolume(UUIDIterator mrcAddresses, Auth auth, UserCredentials userCredentials,
String volumeName) throws IOException, PosixErrorException, AddressToUUIDNotFoundException {
final MRCServiceClient mrcServiceClient = new MRCServiceClient(this.networkClient, null);
RPCCaller.<String, emptyResponse> syncCall(SERVICES.MRC, userCredentials, auth, this.options, this,
mrcAddresses, true, volumeName, new CallGenerator<String, emptyResponse>() {
@SuppressWarnings("unchecked")
@Override
public RPCResponse<emptyResponse> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, String input) throws IOException {
return mrcServiceClient.xtreemfs_rmvol(server, authHeader, userCreds, input);
}
});
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#listVolumes(java.lang.String)
*/
@Override
public Volumes listVolumes(String mrcAddress) throws IOException, PosixErrorException,
AddressToUUIDNotFoundException {
UUIDIterator iteratorWithAddresses = new UUIDIterator();
iteratorWithAddresses.addUUID(mrcAddress);
return listVolumes(iteratorWithAddresses);
}
@Override
public Volumes listVolumes(List<String> mrcAddresses) throws IOException, PosixErrorException,
AddressToUUIDNotFoundException {
UUIDIterator iteratorWithAddresses = new UUIDIterator();
iteratorWithAddresses.addUUIDs(mrcAddresses);
return listVolumes(iteratorWithAddresses);
}
private Volumes listVolumes(UUIDIterator uuidIteratorWithAddresses) throws IOException,
PosixErrorException, AddressToUUIDNotFoundException {
final MRCServiceClient mrcServiceClient = new MRCServiceClient(this.networkClient, null);
// use bogus user credentials
UserCredentials userCredentials = UserCredentials.newBuilder().setUsername("xtreemfs").build();
Volumes volumes = RPCCaller.<emptyRequest, Volumes> syncCall(SERVICES.MRC, userCredentials,
this.authBogus, this.options, this, uuidIteratorWithAddresses, true,
emptyRequest.getDefaultInstance(), new CallGenerator<emptyRequest, Volumes>() {
@Override
public RPCResponse<Volumes> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, emptyRequest input) throws IOException {
return mrcServiceClient.xtreemfs_lsvol(server, authHeader, userCreds, input);
};
});
return volumes;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#listVolumes()
*/
@Override
public Volumes listVolumes() throws IOException {
ServiceSet sSet = RPCCaller.<String, ServiceSet> syncCall(SERVICES.DIR,
this.dirServiceUserCredentials, this.dirServiceAuth, this.options, this,
this.dirServiceAddresses, true, null, new CallGenerator<String, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, String input) throws IOException {
return ClientImplementation.this.dirServiceClient.xtreemfs_service_get_by_type(
server, authHeader, userCreds, ServiceType.SERVICE_TYPE_VOLUME);
}
});
UUIDIterator iteratorWithAddresses = new UUIDIterator();
for (int i = 0; i < sSet.getServicesCount(); i++) {
for (KeyValuePair kvp : sSet.getServices(i).getData().getDataList()) {
if (kvp.getKey().substring(0, 3).equals("mrc")) {
String mrcUuid = kvp.getValue();
iteratorWithAddresses.addUUID(uuidToAddress(mrcUuid));
break;
}
}
}
return listVolumes(iteratorWithAddresses);
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#listVolumeNames()
*/
@Override
public String[] listVolumeNames() throws IOException {
ServiceSet sSet = RPCCaller.<String, ServiceSet> syncCall(SERVICES.DIR,
this.dirServiceUserCredentials, this.dirServiceAuth, this.options, this,
this.dirServiceAddresses, true, null, new CallGenerator<String, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, String input) throws IOException {
return ClientImplementation.this.dirServiceClient.xtreemfs_service_get_by_type(
server, authHeader, userCreds, ServiceType.SERVICE_TYPE_VOLUME);
}
});
String[] volNames = new String[sSet.getServicesCount()];
for (int i = 0; i < volNames.length; i++) {
volNames[i] = sSet.getServices(i).getName();
}
return volNames;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#listServers()
*/
@Override
public Map<String, Service> listServers() throws IOException, PosixErrorException {
// access the list of servers at the DIR
ServiceSet osds = RPCCaller.<String, ServiceSet> syncCall(SERVICES.DIR,
this.dirServiceUserCredentials, this.dirServiceAuth, this.options, this,
this.dirServiceAddresses, true, null, new CallGenerator<String, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, String input) throws IOException {
return ClientImplementation.this.dirServiceClient.xtreemfs_service_get_by_type(
server, authHeader, userCreds, ServiceType.SERVICE_TYPE_MIXED);
}
});
Map<String, Service> serviceConfigs = new HashMap<String, Service>();
for (Service service : osds.getServicesList()) {
if (service.getType() == ServiceType.SERVICE_TYPE_MRC
|| service.getType() == ServiceType.SERVICE_TYPE_OSD) {
serviceConfigs.put(uuidToAddress(service.getUuid()), service);
}
}
return serviceConfigs;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.Client#listOSDsAndAttributes()
*/
@Override
public Map<String, Service> listOSDsAndAttributes() throws IOException, PosixErrorException {
// access the list of OSDs
ServiceSet osds = RPCCaller.<String, ServiceSet> syncCall(SERVICES.DIR,
this.dirServiceUserCredentials, this.dirServiceAuth, this.options, this,
this.dirServiceAddresses, true, null, new CallGenerator<String, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, String input) throws IOException {
return ClientImplementation.this.dirServiceClient.xtreemfs_service_get_by_type(
server, authHeader, userCreds, ServiceType.SERVICE_TYPE_OSD);
}
});
Map<String, Service> osdConfigs = new HashMap<String, Service>();
for (Service service : osds.getServicesList()) {
// // access the config files of each OSD
// Configuration config = RPCCaller.<String, Configuration> syncCall(SERVICES.DIR,
// this.dirServiceUserCredentials,
// this.dirServiceAuth, this.options, this, this.dirServiceAddresses, true, uuid.getUuid(),
// new CallGenerator<String, Configuration>() {
// @Override
// public RPCResponse<Configuration> executeCall(InetSocketAddress server, Auth authHeader,
// UserCredentials userCreds, String input) throws IOException {
// return ClientImplementation.this.dirServiceClient.xtreemfs_configuration_get(server,
// authHeader, userCreds, input);
// }
// });
osdConfigs.put(service.getUuid(), service);
}
return osdConfigs;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.UUIDResolver#uuidToAddress(java.lang. String, java.lang.String)
*/
@Override
public String uuidToAddress(String uuid) throws AddressToUUIDNotFoundException {
// The uuid must never be empty.
assert (!uuid.isEmpty());
String address = "";
ServiceUUID serviceUuid = new ServiceUUID(uuid, this.uuidResolver);
try {
serviceUuid.resolve();
address = serviceUuid.getAddressString();
} catch (UnknownUUIDException e) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this,
"UUID: SERVICE NOT FOUND FOR UUID %S", uuid);
}
throw new AddressToUUIDNotFoundException(uuid);
}
return address;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.UUIDResolver#volumeNameToMRCUUID(java .lang.String,
* java.lang.String)
*/
@Override
public String volumeNameToMRCUUID(String volumeName) throws VolumeNotFoundException,
AddressToUUIDNotFoundException {
assert (!volumeName.isEmpty());
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "Searching MRC for volume %s",
volumeName);
}
// Check if there is an '@' in the volume. Everything behind the '@' is
// the snapshot, cut if off.
String parsedVolumeName = parseVolumeName(volumeName);
ServiceSet sSet;
try {
sSet = getServicesByName(parsedVolumeName);
} catch (IOException e) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "volumeNameToMRCUUID: "
+ "couldn't resolve mrc UUID for volumeName %s Reason: %s", volumeName, e.getMessage());
}
throw new VolumeNotFoundException(parsedVolumeName);
}
// check if there is an service which is a VOLUME and then filter the
// MRC of this volume
// from its ServiceDataMap.
String mrcUuid = "";
for (Service service : sSet.getServicesList()) {
if (service.getType().equals(ServiceType.SERVICE_TYPE_VOLUME)
&& service.getName().equals(parsedVolumeName)) {
for (KeyValuePair kvp : service.getData().getDataList()) {
if (kvp.getKey().substring(0, 3).equals("mrc")) {
mrcUuid = kvp.getValue();
break;
}
}
// don't check other services if there are any left when an
// mrcUuid is already determined.
if (!mrcUuid.isEmpty()) {
break;
}
}
}
// Error Handling
if (mrcUuid.isEmpty()) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "No MRC found for volume $s.",
parsedVolumeName);
}
throw new VolumeNotFoundException(parsedVolumeName);
}
return mrcUuid;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.libxtreemfs.UUIDResolver#volumeNameToMRCUUID(java .lang.String,
* org.xtreemfs.common.libxtreemfs.UUIDIterator)
*/
@Override
public void volumeNameToMRCUUID(String volumeName, UUIDIterator uuidIterator)
throws VolumeNotFoundException, AddressToUUIDNotFoundException {
assert (uuidIterator != null);
assert (!volumeName.isEmpty());
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "Searching MRC for volume %s",
volumeName);
}
// Check if there is a @ in the volume_name.
// Everything behind the @ has to be removed as it identifies the snapshot.
String parsedVolumeName = parseVolumeName(volumeName);
ServiceSet sSet;
try {
sSet = getServicesByName(parsedVolumeName);
} catch (IOException e) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "volumeNameToMRCUUID: "
+ "couldn't resolve mrc UUID for volumeName %s Reason: %s", volumeName, e.getMessage());
}
throw new VolumeNotFoundException(parsedVolumeName);
}
// Iterate over ServiceSet to find an appropriate MRC
boolean mrcFound = false;
for (Service service : sSet.getServicesList()) {
if (service.getType().equals(ServiceType.SERVICE_TYPE_VOLUME)
&& service.getName().equals(parsedVolumeName)) {
for (KeyValuePair kvp : service.getData().getDataList()) {
if (kvp.getKey().substring(0, 3).equals("mrc")) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "MRC with UUID: %s"
+ " added (key: %s).", kvp.getValue(), kvp.getKey());
}
uuidIterator.addUUID(kvp.getValue());
mrcFound = true;
}
}
}
}
// Error handling
if (!mrcFound) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "No MRC found for volume $s.",
parsedVolumeName);
}
throw new VolumeNotFoundException(parsedVolumeName);
}
}
@Override
public List<String> volumeNameToMRCUUIDs(String volumeName) throws VolumeNotFoundException,
AddressToUUIDNotFoundException {
assert (!volumeName.isEmpty());
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "Searching MRC for volume %s", volumeName);
}
// Check if there is a @ in the volume_name.
// Everything behind the @ has to be removed as it identifies the snapshot.
String parsedVolumeName = parseVolumeName(volumeName);
ServiceSet sSet;
try {
sSet = getServicesByName(parsedVolumeName);
} catch (IOException e) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "volumeNameToMRCUUID: "
+ "couldn't resolve mrc UUID for volumeName %s Reason: %s", volumeName, e.getMessage());
}
throw new VolumeNotFoundException(parsedVolumeName);
}
// Iterate over ServiceSet to find an appropriate MRC
LinkedList<String> result = new LinkedList<String>();
for (Service service : sSet.getServicesList()) {
if (service.getType().equals(ServiceType.SERVICE_TYPE_VOLUME) && service.getName().equals(parsedVolumeName)) {
for (KeyValuePair kvp : service.getData().getDataList()) {
if (kvp.getKey().substring(0, 3).equals("mrc")) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "MRC with UUID: %s"
+ " added (key: %s).", kvp.getValue(), kvp.getKey());
}
result.add(kvp.getValue());
}
}
}
}
// Error handling
if (result.isEmpty()) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this, "No MRC found for volume $s.",
parsedVolumeName);
}
throw new VolumeNotFoundException(parsedVolumeName);
}
return result;
}
/**
* If volumeName contains an '@', cut off everything after the at because this belongs to the snapshot.
* The real volumename is everything before the '@'.
*
* @param volumeName
* The volumeName that should be parsed
* @return String The parsed volume name.
*
*/
private String parseVolumeName(String volumeName) {
int pos = 0;
String parsedVolumeName;
if ((pos = volumeName.indexOf('@')) == -1) {
parsedVolumeName = volumeName;
} else {
parsedVolumeName = volumeName.substring(0, pos);
}
return parsedVolumeName;
}
// Methods for AdminClient
private Auth StringToAuth(String password) {
return Auth.newBuilder().setAuthType(AuthType.AUTH_PASSWORD)
.setAuthPasswd(AuthPassword.newBuilder().setPassword(password).build()).build();
}
public void startCleanUp(String osdUUID, String password, boolean remove, boolean deleteVolumes, boolean restore,
boolean removeMetdata, int metaDataTimeoutS) throws IOException {
try {
xtreemfs_cleanup_startRequest request = xtreemfs_cleanup_startRequest.newBuilder()
.setRemoveZombies(remove).setRemoveUnavailVolume(deleteVolumes).setLostAndFound(restore)
.setDeleteMetadata(removeMetdata).setMetadataTimeout(metaDataTimeoutS)
.build();
Auth pw = StringToAuth(password);
UUIDIterator it = new UUIDIterator();
it.addUUID(osdUUID);
RPCCaller.<xtreemfs_cleanup_startRequest, emptyResponse> syncCall(SERVICES.OSD,
RPCAuthentication.userService, pw, options, this, it, false, request,
new CallGenerator<xtreemfs_cleanup_startRequest, emptyResponse>() {
@Override
@SuppressWarnings("unchecked")
public RPCResponse<emptyResponse> executeCall(InetSocketAddress server,
Auth authHeader, UserCredentials userCreds,
xtreemfs_cleanup_startRequest input) throws IOException {
return osdServiceClient.xtreemfs_cleanup_start(server, authHeader, userCreds, input);
}
});
} catch (Exception e) {
throw new IOException("Cleanup could not be started on the given OSD, because: " + e.getMessage());
}
}
public void startVersionCleanUp(String osdUUID, String password) throws IOException {
try {
Auth pw = StringToAuth(password);
UUIDIterator it = new UUIDIterator();
it.addUUID(osdUUID);
RPCCaller.<emptyRequest, emptyResponse> syncCall(SERVICES.OSD, RPCAuthentication.userService, pw,
options, this, it, false, null, new CallGenerator<emptyRequest, emptyResponse>() {
@Override
@SuppressWarnings("unchecked")
public RPCResponse<emptyResponse> executeCall(InetSocketAddress server,
Auth authHeader, UserCredentials userCreds, emptyRequest input)
throws IOException {
return osdServiceClient.xtreemfs_cleanup_versions_start(server, authHeader,
userCreds);
}
});
} catch (Exception e) {
throw new IOException("Version cleanup could not be started on the given OSD, because: "
+ e.getMessage());
}
}
public void stopCleanUp(String osdUUID, String password) throws IOException {
Auth pw = StringToAuth(password);
UUIDIterator it = new UUIDIterator();
it.addUUID(osdUUID);
RPCCaller.<emptyRequest, emptyResponse> syncCall(SERVICES.OSD, RPCAuthentication.userService, pw,
options, this, it, false, null, new CallGenerator<emptyRequest, emptyResponse>() {
@Override
@SuppressWarnings("unchecked")
public RPCResponse<emptyResponse> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, emptyRequest input) throws IOException,
PosixErrorException {
return osdServiceClient.xtreemfs_cleanup_stop(server, authHeader, userCreds);
}
});
}
public boolean isRunningCleanUp(String osdUUID, String password) throws IOException {
Auth pw = StringToAuth(password);
UUIDIterator it = new UUIDIterator();
it.addUUID(osdUUID);
xtreemfs_cleanup_is_runningResponse response = RPCCaller
.<emptyRequest, xtreemfs_cleanup_is_runningResponse> syncCall(SERVICES.OSD,
RPCAuthentication.userService, pw, options, this, it, false, null,
new CallGenerator<emptyRequest, xtreemfs_cleanup_is_runningResponse>() {
@Override
public RPCResponse<xtreemfs_cleanup_is_runningResponse> executeCall(
InetSocketAddress server, Auth authHeader, UserCredentials userCreds,
emptyRequest input) throws IOException, PosixErrorException {
return osdServiceClient.xtreemfs_cleanup_is_running(server, authHeader,
userCreds);
}
});
assert (response != null);
return response.getIsRunning();
}
public String getCleanUpState(String osdUUID, String password) throws IOException {
Auth pw = StringToAuth(password);
UUIDIterator it = new UUIDIterator();
it.addUUID(osdUUID);
xtreemfs_cleanup_statusResponse response = RPCCaller
.<emptyRequest, xtreemfs_cleanup_statusResponse> syncCall(SERVICES.OSD,
RPCAuthentication.userService, pw, options, this, it, false, null,
new CallGenerator<emptyRequest, xtreemfs_cleanup_statusResponse>() {
@Override
public RPCResponse<xtreemfs_cleanup_statusResponse> executeCall(
InetSocketAddress server, Auth authHeader, UserCredentials userCreds,
emptyRequest input) throws IOException, PosixErrorException {
return osdServiceClient
.xtreemfs_cleanup_status(server, authHeader, userCreds);
}
});
assert (response != null);
return response.getStatus();
}
public List<String> getCleanUpResult(String osdUUID, String password) throws IOException {
Auth pw = StringToAuth(password);
UUIDIterator it = new UUIDIterator();
it.addUUID(osdUUID);
xtreemfs_cleanup_get_resultsResponse response = RPCCaller
.<emptyRequest, xtreemfs_cleanup_get_resultsResponse> syncCall(SERVICES.OSD,
RPCAuthentication.userService, pw, options, this, it, false, null,
new CallGenerator<emptyRequest, xtreemfs_cleanup_get_resultsResponse>() {
@Override
public RPCResponse<xtreemfs_cleanup_get_resultsResponse> executeCall(
InetSocketAddress server, Auth authHeader, UserCredentials userCreds,
emptyRequest input) throws IOException, PosixErrorException {
return osdServiceClient.xtreemfs_cleanup_get_results(server, authHeader,
userCreds);
}
});
assert (response != null);
return response.getResultsList();
}
public ServiceSet getServiceByType(ServiceType serviceType) throws IOException {
serviceGetByTypeRequest request = serviceGetByTypeRequest.newBuilder().setType(serviceType).build();
ServiceSet sSet = RPCCaller.<serviceGetByTypeRequest, ServiceSet> syncCall(SERVICES.DIR,
RPCAuthentication.userService, RPCAuthentication.authNone, options, this,
dirServiceAddresses, true, request, new CallGenerator<serviceGetByTypeRequest, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, serviceGetByTypeRequest input) throws IOException {
return dirServiceClient.xtreemfs_service_get_by_type(server, authHeader, userCreds,
input);
}
});
assert (sSet != null);
return sSet;
}
public Service getServiceByUUID(String uuid) throws IOException {
serviceGetByUUIDRequest request = serviceGetByUUIDRequest.newBuilder().setName(uuid).build();
ServiceSet sSet = RPCCaller.<serviceGetByUUIDRequest, ServiceSet> syncCall(SERVICES.DIR,
RPCAuthentication.userService, RPCAuthentication.authNone, options, this,
dirServiceAddresses, true, request, new CallGenerator<serviceGetByUUIDRequest, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, serviceGetByUUIDRequest input) throws IOException {
return dirServiceClient.xtreemfs_service_get_by_uuid(server, authHeader, userCreds,
input);
}
});
assert (sSet != null);
if (sSet.getServicesCount() == 0) {
throw new IOException("No Service with UUID " + uuid + " available");
}
return sSet.getServices(0);
}
ServiceSet getServicesByName(String name) throws IOException {
serviceGetByNameRequest request = serviceGetByNameRequest.newBuilder().setName(name).build();
ServiceSet sSet = RPCCaller.<serviceGetByNameRequest, ServiceSet> syncCall(SERVICES.DIR,
dirServiceUserCredentials, dirServiceAuth, options, this, dirServiceAddresses, true, request,
new CallGenerator<serviceGetByNameRequest, ServiceSet>() {
@Override
public RPCResponse<ServiceSet> executeCall(InetSocketAddress server, Auth authHeader,
UserCredentials userCreds, serviceGetByNameRequest input) throws IOException {
return dirServiceClient.xtreemfs_service_get_by_name(server, authHeader, userCreds, input);
}
});
assert (sSet != null);
return sSet;
}
public void setOSDServiceStatus(String osdUUID, ServiceStatus serviceStatus) throws IOException {
// Get OSD services
Service osdService = getServiceByUUID(osdUUID);
// Change service status
List<KeyValuePair> data = new LinkedList<KeyValuePair>(osdService.getData().getDataList());
KeyValuePairs.putValue(data, HeartbeatThread.STATUS_ATTR, Integer.toString(serviceStatus.getNumber()));
KeyValuePairs.putValue(data, HeartbeatThread.DO_NOT_SET_LAST_UPDATED, Boolean.toString(true));
ServiceDataMap dataMap = ServiceDataMap.newBuilder().addAllData(data).build();
osdService = osdService.toBuilder().setData(dataMap).build();
// Send changed service status to DIR
serviceRegisterRequest request = serviceRegisterRequest.newBuilder().setService(osdService).build();
RPCCaller.<serviceRegisterRequest, serviceRegisterResponse> syncCall(SERVICES.DIR,
RPCAuthentication.userService, RPCAuthentication.authNone, options, this,
dirServiceAddresses, true, request,
new CallGenerator<serviceRegisterRequest, serviceRegisterResponse>() {
@Override
public RPCResponse<serviceRegisterResponse> executeCall(InetSocketAddress server,
Auth authHeader, UserCredentials userCreds, serviceRegisterRequest input)
throws IOException {
return dirServiceClient.xtreemfs_service_register(server, RPCAuthentication.authNone,
userCreds, input);
}
});
}
public ServiceStatus getOSDServiceStatus(String osdUUID) throws IOException {
Service osdService = getServiceByUUID(osdUUID);
String serviceStatus = KeyValuePairs.getValue(osdService.getData().getDataList(),
HeartbeatThread.STATUS_ATTR);
return ServiceStatus.valueOf(Integer.valueOf(serviceStatus));
}
public Set<String> getRemovedOsds() throws IOException {
Set<String> removedOSDs = new TreeSet<String>();
String statusRemoved = Integer.toString(ServiceStatus.SERVICE_STATUS_REMOVED.getNumber());
ServiceSet servs = getServiceByType(ServiceType.SERVICE_TYPE_OSD);
for (Service serv : servs.getServicesList()) {
String hbAttr = KeyValuePairs.getValue(serv.getData().getDataList(), HeartbeatThread.STATUS_ATTR);
if (hbAttr != null && hbAttr.equalsIgnoreCase(statusRemoved)) {
removedOSDs.add(serv.getUuid());
}
}
return removedOSDs;
}
}