use of com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedSMBShareMap in project coprhd-controller by CoprHD.
the class VNXFileCommunicationInterface method associateCifsExportWithFS.
private void associateCifsExportWithFS(UnManagedFileSystem vnxufs, String exportPath, Map<String, String> fsExportInfo, StoragePort storagePort) {
try {
// Assign storage port to unmanaged FS
if (storagePort != null) {
StringSet storagePorts = new StringSet();
storagePorts.add(storagePort.getId().toString());
vnxufs.getFileSystemInformation().remove(UnManagedFileSystem.SupportedFileSystemInformation.STORAGE_PORT.toString());
vnxufs.getFileSystemInformation().put(UnManagedFileSystem.SupportedFileSystemInformation.STORAGE_PORT.toString(), storagePorts);
}
String shareName = fsExportInfo.get(VNXFileConstants.SHARE_NAME);
String mountPoint = getMountPount(shareName, storagePort);
UnManagedSMBFileShare unManagedSMBFileShare = new UnManagedSMBFileShare();
unManagedSMBFileShare.setName(shareName);
unManagedSMBFileShare.setMountPoint(mountPoint);
unManagedSMBFileShare.setPath(exportPath);
// setting to default permission type for VNX
unManagedSMBFileShare.setPermissionType(FileControllerConstants.CIFS_SHARE_PERMISSION_TYPE_ALLOW);
unManagedSMBFileShare.setDescription(fsExportInfo.get(VNXFileConstants.SHARE_COMMENT));
int maxUsers = Integer.MAX_VALUE;
if (Long.parseLong(fsExportInfo.get(VNXFileConstants.SHARE_MAXUSR)) < Integer.MAX_VALUE) {
maxUsers = Integer.parseInt(fsExportInfo.get(VNXFileConstants.SHARE_MAXUSR));
}
unManagedSMBFileShare.setMaxUsers(maxUsers);
unManagedSMBFileShare.setPortGroup(storagePort.getPortGroup());
unManagedSMBFileShare.setPermission(ShareACL.SupportedPermissions.change.toString());
UnManagedSMBShareMap currUnManagedShareMap = vnxufs.getUnManagedSmbShareMap();
if (currUnManagedShareMap == null) {
currUnManagedShareMap = new UnManagedSMBShareMap();
vnxufs.setUnManagedSmbShareMap(currUnManagedShareMap);
}
if (currUnManagedShareMap.get(shareName) == null) {
currUnManagedShareMap.put(shareName, unManagedSMBFileShare);
_logger.info("associateCifsExportWithFS - no SMBs already exists for share {}", shareName);
} else {
// Remove the existing and add the new share
currUnManagedShareMap.remove(shareName);
currUnManagedShareMap.put(shareName, unManagedSMBFileShare);
_logger.warn("associateSMBShareMapWithFS - Identical export already exists for mount path {} Overwrite", shareName);
}
} catch (Exception ex) {
_logger.warn("VNX file share retrieve processor failed for path {}, cause {}", exportPath, ex);
}
}
use of com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedSMBShareMap in project coprhd-controller by CoprHD.
the class IsilonCommunicationInterface method setUnmanagedCifsShareACL.
/**
* get UnManaged Cifs Shares and their ACLs
*
* @param unManagedFileSystem
* @param smbShares
* @param unManagedCifsShareACLList
* @param fsPath
* @param isilonApi
*/
private void setUnmanagedCifsShareACL(UnManagedFileSystem unManagedFileSystem, HashSet<String> smbShares, List<UnManagedCifsShareACL> unManagedCifsShareACLList, StoragePort storagePort, String fsname, String zoneName, StorageSystem storageSystem, IsilonApi isilonApi, List<UnManagedCifsShareACL> oldUnManagedCifsShareACLList) {
_log.debug("Set CIFS shares and their respective ACL of UMFS: {} from Isilon SMB share details - start", fsname);
if (null != smbShares && !smbShares.isEmpty()) {
UnManagedSMBShareMap unManagedSmbShareMap = null;
if (null == unManagedFileSystem.getUnManagedSmbShareMap()) {
unManagedSmbShareMap = new UnManagedSMBShareMap();
unManagedFileSystem.setUnManagedSmbShareMap(unManagedSmbShareMap);
}
unManagedSmbShareMap = unManagedFileSystem.getUnManagedSmbShareMap();
UnManagedSMBFileShare unManagedSMBFileShare = null;
for (String shareId : smbShares) {
// get smb share details
IsilonSMBShare isilonSMBShare = getIsilonSMBShare(isilonApi, shareId, zoneName);
if (null != isilonSMBShare) {
unManagedSMBFileShare = new UnManagedSMBFileShare();
unManagedSMBFileShare.setName(isilonSMBShare.getName());
unManagedSMBFileShare.setDescription(isilonSMBShare.getDescription());
unManagedSMBFileShare.setNativeId(shareId);
unManagedSMBFileShare.setMountPoint("\\\\" + storagePort.getPortNetworkId() + "\\" + isilonSMBShare.getName());
unManagedSMBFileShare.setPath(isilonSMBShare.getPath());
unManagedSMBFileShare.setMaxUsers(-1);
// setting the dummy permission.This is not used by isilon, but used by other storage system
unManagedSMBFileShare.setPermission(FileControllerConstants.CIFS_SHARE_PERMISSION_CHANGE);
unManagedSMBFileShare.setPermissionType(FileControllerConstants.CIFS_SHARE_PERMISSION_TYPE_ALLOW);
// set Unmanaged SMB Share
unManagedSmbShareMap.put(isilonSMBShare.getName(), unManagedSMBFileShare);
_log.info("SMB share id {} ", shareId);
_log.info("SMB share name {} and fs mount point {} ", unManagedSMBFileShare.getName(), unManagedSMBFileShare.getMountPoint());
// process ACL permission
UnManagedCifsShareACL unManagedCifsShareACL = null;
int aclSize = 0;
List<IsilonSMBShare.Permission> permissionList = isilonSMBShare.getPermissions();
for (IsilonSMBShare.Permission permission : permissionList) {
if (FileControllerConstants.CIFS_SHARE_PERMISSION_TYPE_ALLOW.equalsIgnoreCase(permission.getPermissionType())) {
aclSize++;
_log.debug("IsilonSMBShare: [{}] permission details: {}", isilonSMBShare.getName(), permission.toString());
unManagedCifsShareACL = new UnManagedCifsShareACL();
// Set share name
unManagedCifsShareACL.setShareName(isilonSMBShare.getName());
// Set permission
unManagedCifsShareACL.setPermission(permission.getPermission());
// We take only username and we can ignore type and id
// Set user
unManagedCifsShareACL.setUser(permission.getTrustee().getName());
// Set filesystem id
unManagedCifsShareACL.setFileSystemId(unManagedFileSystem.getId());
unManagedCifsShareACL.setId(URIUtil.createId(UnManagedCifsShareACL.class));
String fsShareNativeId = unManagedCifsShareACL.getFileSystemShareACLIndex();
_log.info("UMFS Share ACL index {}", fsShareNativeId);
String fsUnManagedFileShareNativeGuid = NativeGUIDGenerator.generateNativeGuidForPreExistingFileShare(storageSystem, fsShareNativeId);
_log.info("Native GUID {}", fsUnManagedFileShareNativeGuid);
// set native guid, so each entry unique
unManagedCifsShareACL.setNativeGuid(fsUnManagedFileShareNativeGuid);
// Check whether the CIFS share ACL was present in ViPR DB.
UnManagedCifsShareACL existingCifsShareACL = checkUnManagedFsCifsACLExistsInDB(_dbClient, unManagedCifsShareACL.getNativeGuid());
if (existingCifsShareACL != null) {
// delete the existing acl
existingCifsShareACL.setInactive(true);
oldUnManagedCifsShareACLList.add(existingCifsShareACL);
}
unManagedCifsShareACLList.add(unManagedCifsShareACL);
}
}
_log.debug("ACL size of share: [{}] is {}", isilonSMBShare.getName(), aclSize);
}
}
if (!unManagedSmbShareMap.isEmpty()) {
unManagedFileSystem.setHasShares(true);
}
}
}
use of com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedSMBShareMap in project coprhd-controller by CoprHD.
the class IsilonCommunicationInterface method createUnManagedFileSystem.
/**
* create StorageFileSystem Info Object
*
* @param unManagedFileSystem
* @param unManagedFileSystemNativeGuid
* @param storageSystem
* @param fileSystem
* @return UnManagedFileSystem
* @throws IOException
* @throws IsilonCollectionException
*/
private UnManagedFileSystem createUnManagedFileSystem(UnManagedFileSystem unManagedFileSystem, String unManagedFileSystemNativeGuid, StorageSystem storageSystem, StoragePool pool, NASServer nasServer, FileShare fileSystem) throws IOException, IsilonCollectionException {
if (null == unManagedFileSystem) {
unManagedFileSystem = new UnManagedFileSystem();
unManagedFileSystem.setId(URIUtil.createId(UnManagedFileSystem.class));
unManagedFileSystem.setNativeGuid(unManagedFileSystemNativeGuid);
unManagedFileSystem.setStorageSystemUri(storageSystem.getId());
if (null != pool) {
unManagedFileSystem.setStoragePoolUri(pool.getId());
}
unManagedFileSystem.setHasExports(false);
unManagedFileSystem.setHasShares(false);
unManagedFileSystem.setHasNFSAcl(false);
}
if (null == unManagedFileSystem.getExtensions()) {
unManagedFileSystem.setExtensions(new StringMap());
}
Map<String, StringSet> unManagedFileSystemInformation = new HashMap<String, StringSet>();
StringMap unManagedFileSystemCharacteristics = new StringMap();
unManagedFileSystemCharacteristics.put(UnManagedFileSystem.SupportedFileSystemCharacterstics.IS_SNAP_SHOT.toString(), FALSE);
unManagedFileSystemCharacteristics.put(UnManagedFileSystem.SupportedFileSystemCharacterstics.IS_THINLY_PROVISIONED.toString(), TRUE);
unManagedFileSystemCharacteristics.put(UnManagedFileSystem.SupportedFileSystemCharacterstics.IS_FILESYSTEM_EXPORTED.toString(), FALSE);
if (null != pool) {
StringSet pools = new StringSet();
pools.add(pool.getId().toString());
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.STORAGE_POOL.toString(), pools);
StringSet matchedVPools = DiscoveryUtils.getMatchedVirtualPoolsForPool(_dbClient, pool.getId(), unManagedFileSystemCharacteristics.get(UnManagedFileSystem.SupportedFileSystemCharacterstics.IS_THINLY_PROVISIONED.toString()));
_log.debug("Matched Pools : {}", Joiner.on("\t").join(matchedVPools));
if (null == matchedVPools || matchedVPools.isEmpty()) {
// clear all existing supported vpools.
unManagedFileSystem.getSupportedVpoolUris().clear();
} else {
// replace with new StringSet
unManagedFileSystem.getSupportedVpoolUris().replace(matchedVPools);
_log.info("Replaced Pools :" + Joiner.on("\t").join(unManagedFileSystem.getSupportedVpoolUris()));
}
}
if (null != nasServer) {
StringSet storagePorts = new StringSet();
if (nasServer.getStoragePorts() != null && !nasServer.getStoragePorts().isEmpty()) {
storagePorts.addAll(nasServer.getStoragePorts());
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.STORAGE_PORT.toString(), storagePorts);
_log.info("StoragePorts :" + Joiner.on("\t").join(storagePorts));
}
StringSet nasServerSet = new StringSet();
nasServerSet.add(nasServer.getId().toString());
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.NAS.toString(), nasServerSet);
_log.debug("nasServer uri id {}", nasServer.getId().toString());
}
unManagedFileSystemCharacteristics.put(UnManagedFileSystem.SupportedFileSystemCharacterstics.IS_INGESTABLE.toString(), TRUE);
if (null != storageSystem) {
StringSet systemTypes = new StringSet();
systemTypes.add(storageSystem.getSystemType());
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.SYSTEM_TYPE.toString(), systemTypes);
}
// Set attributes of FileSystem
StringSet fsPath = new StringSet();
fsPath.add(fileSystem.getNativeId());
StringSet fsMountPath = new StringSet();
fsMountPath.add(fileSystem.getMountPath());
StringSet fsName = new StringSet();
fsName.add(fileSystem.getName());
StringSet fsId = new StringSet();
fsId.add(fileSystem.getNativeId());
StringSet softLimit = new StringSet();
softLimit.add(fileSystem.getSoftLimit().toString());
StringSet softGrace = new StringSet();
softGrace.add(fileSystem.getSoftGracePeriod().toString());
StringSet notificationLimit = new StringSet();
notificationLimit.add(fileSystem.getNotificationLimit().toString());
unManagedFileSystem.setLabel(fileSystem.getName());
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.NAME.toString(), fsName);
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.NATIVE_ID.toString(), fsId);
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.DEVICE_LABEL.toString(), fsName);
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.PATH.toString(), fsPath);
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.MOUNT_PATH.toString(), fsMountPath);
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.SOFT_LIMIT.toString(), softLimit);
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.SOFT_GRACE.toString(), softGrace);
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.NOTIFICATION_LIMIT.toString(), notificationLimit);
StringSet provisionedCapacity = new StringSet();
long capacity = 0;
if (fileSystem.getCapacity() != null) {
capacity = fileSystem.getCapacity();
}
provisionedCapacity.add(String.valueOf(capacity));
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.PROVISIONED_CAPACITY.toString(), provisionedCapacity);
StringSet allocatedCapacity = new StringSet();
long usedCapacity = 0;
if (fileSystem.getUsedCapacity() != null) {
usedCapacity = fileSystem.getUsedCapacity();
}
allocatedCapacity.add(String.valueOf(usedCapacity));
unManagedFileSystemInformation.put(UnManagedFileSystem.SupportedFileSystemInformation.ALLOCATED_CAPACITY.toString(), allocatedCapacity);
String quotaId = fileSystem.getExtensions().get(QUOTA);
if (quotaId != null) {
unManagedFileSystem.getExtensions().put(QUOTA, quotaId);
}
_log.debug("Quota : {} : {}", quotaId, fileSystem.getPath());
// Add fileSystemInformation and Characteristics.
unManagedFileSystem.addFileSystemInformation(unManagedFileSystemInformation);
unManagedFileSystem.addFileSystemCharacterstcis(unManagedFileSystemCharacteristics);
// Initialize ExportMap
unManagedFileSystem.setFsUnManagedExportMap(new UnManagedFSExportMap());
// Initialize SMBMap
unManagedFileSystem.setUnManagedSmbShareMap(new UnManagedSMBShareMap());
return unManagedFileSystem;
}
use of com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedSMBShareMap in project coprhd-controller by CoprHD.
the class NetAppFileCommunicationInterface method discoverUnManagedCifsShares.
/**
* discover the unmanaged cifs shares and add shares to vipr db
*
* @param profile
*/
private void discoverUnManagedCifsShares(AccessProfile profile) {
URI systemId = profile.getSystemId();
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, systemId);
if (null == storageSystem) {
return;
}
String detailedStatusMessage = "Discovery of NetApp Unmanaged Cifs shares started";
NetAppApi netAppApi = new NetAppApi.Builder(storageSystem.getIpAddress(), storageSystem.getPortNumber(), storageSystem.getUsername(), storageSystem.getPassword()).https(true).build();
Collection<String> attrs = new ArrayList<String>();
for (String property : ntpPropertiesList) {
attrs.add(SupportedNtpFileSystemInformation.getFileSystemInformation(property));
}
try {
// Used to Save the Acl to DB
List<UnManagedCifsShareACL> unManagedCifsShareACLList = new ArrayList<UnManagedCifsShareACL>();
List<UnManagedCifsShareACL> oldunManagedCifsShareACLList = new ArrayList<UnManagedCifsShareACL>();
List<Map<String, String>> fileSystemInfo = netAppApi.listVolumeInfo(null, attrs);
List<VFilerInfo> vFilers = netAppApi.listVFilers(null);
// Get All cifs shares and ACLs
List<Map<String, String>> listShares = netAppApi.listShares(null);
if (listShares != null && !listShares.isEmpty()) {
_logger.info("total no of shares in netapp system (s) {}", listShares.size());
}
HashSet<UnManagedSMBFileShare> unManagedSMBFileShareHashSet = null;
// prepare the unmanagedSmbshare
HashMap<String, HashSet<UnManagedSMBFileShare>> unMangedSMBFileShareMapSet = getAllCifsShares(listShares);
for (String key : unMangedSMBFileShareMapSet.keySet()) {
String filesystem = key;
unManagedSMBFileShareHashSet = unMangedSMBFileShareMapSet.get(key);
_logger.info("FileSystem Path {}", filesystem);
String nativeId = null;
if (!filesystem.startsWith(VOL_ROOT_NO_SLASH)) {
nativeId = VOL_ROOT_NO_SLASH + filesystem;
} else {
nativeId = filesystem;
}
// Ignore root volume and don't pull it into ViPR db.
if (filesystem.contains(ROOT_VOL)) {
_logger.info("Ignore and not discover root filesystem {} on NTP array", filesystem);
continue;
}
// Ignore snapshots and don't pull it into ViPR db.
if (filesystem.contains(SNAPSHOT)) {
_logger.info("Ignore exports for snapshot {}", filesystem);
continue;
}
String shareNativeId = getFSPathIfSubDirectoryExport(nativeId);
String fsUnManagedFsNativeGuid = NativeGUIDGenerator.generateNativeGuidForPreExistingFileSystem(storageSystem.getSystemType(), storageSystem.getSerialNumber().toUpperCase(), shareNativeId);
UnManagedFileSystem unManagedFs = checkUnManagedFileSystemExistsInDB(fsUnManagedFsNativeGuid);
boolean fsAlreadyExists = unManagedFs == null ? false : true;
if (fsAlreadyExists) {
_logger.info("retrieve info for file system: " + filesystem);
String vFiler = getOwningVfiler(filesystem, fileSystemInfo);
if (vFiler != null && !vFiler.equalsIgnoreCase(DEFAULT_FILER)) {
_logger.info("Ignoring {} because it is owned by {}", filesystem, vFiler);
continue;
}
String addr = null;
if (vFiler == null || vFiler.isEmpty()) {
// No vfilers, use system storage port
StoragePort port = getStoragePortPool(storageSystem);
addr = port.getPortName();
} else {
// Use IP address of vFiler.
addr = getVfilerAddress(vFiler, vFilers);
}
UnManagedSMBShareMap tempUnManagedSMBShareMap = new UnManagedSMBShareMap();
// add smb shares to FS object
createShareMap(unManagedSMBFileShareHashSet, tempUnManagedSMBShareMap, addr, nativeId);
// add shares to fs object
if (!tempUnManagedSMBShareMap.isEmpty() && tempUnManagedSMBShareMap.size() > 0) {
unManagedFs.setUnManagedSmbShareMap(tempUnManagedSMBShareMap);
unManagedFs.setHasShares(true);
unManagedFs.putFileSystemCharacterstics(UnManagedFileSystem.SupportedFileSystemCharacterstics.IS_FILESYSTEM_EXPORTED.toString(), TRUE);
_logger.debug("SMB Share map for NetApp UMFS {} = {}", unManagedFs.getLabel(), unManagedFs.getUnManagedSmbShareMap());
}
List<UnManagedCifsShareACL> tempUnManagedCifsShareAclList = getACLs(unManagedSMBFileShareHashSet, netAppApi, unManagedFs.getId());
// get the acl details for given fileshare
UnManagedCifsShareACL existingACL = null;
for (UnManagedCifsShareACL unManagedCifsShareACL : tempUnManagedCifsShareAclList) {
_logger.info("Unmanaged File share acls : {}", unManagedCifsShareACL);
String fsShareNativeId = unManagedCifsShareACL.getFileSystemShareACLIndex();
_logger.info("UMFS Share ACL index {}", fsShareNativeId);
String fsUnManagedFileShareNativeGuid = NativeGUIDGenerator.generateNativeGuidForPreExistingFileShare(storageSystem, fsShareNativeId);
_logger.info("Native GUID {}", fsUnManagedFileShareNativeGuid);
unManagedCifsShareACL.setNativeGuid(fsUnManagedFileShareNativeGuid);
// Check whether the CIFS share ACL was present in ViPR DB.
existingACL = checkUnManagedFsCifsACLExistsInDB(_dbClient, unManagedCifsShareACL.getNativeGuid());
if (existingACL == null) {
unManagedCifsShareACLList.add(unManagedCifsShareACL);
} else {
// delete the existing acl
existingACL.setInactive(true);
oldunManagedCifsShareACLList.add(existingACL);
// then add new acl
unManagedCifsShareACLList.add(unManagedCifsShareACL);
}
}
// save the object
{
_dbClient.persistObject(unManagedFs);
_logger.info("File System {} has Shares and their Count is {}", unManagedFs.getId(), tempUnManagedSMBShareMap.size());
}
// Adding this additional logic to avoid OOM
if (!unManagedCifsShareACLList.isEmpty() && unManagedCifsShareACLList.size() >= MAX_UMFS_RECORD_SIZE) {
_logger.info("Saving Number of New UnManagedCifsShareACL(s) {}", unManagedCifsShareACLList.size());
_dbClient.createObject(unManagedCifsShareACLList);
unManagedCifsShareACLList.clear();
}
if (!oldunManagedCifsShareACLList.isEmpty() && oldunManagedCifsShareACLList.size() >= MAX_UMFS_RECORD_SIZE) {
_logger.info("Update Number of Old UnManagedCifsShareACL(s) {}", oldunManagedCifsShareACLList.size());
_dbClient.persistObject(oldunManagedCifsShareACLList);
oldunManagedCifsShareACLList.clear();
}
} else {
_logger.info("FileSystem " + unManagedFs + "is not present in ViPR DB. Hence ignoring " + filesystem + " share");
}
}
//
if (!unManagedCifsShareACLList.isEmpty()) {
_logger.info("Saving Number of New UnManagedCifsShareACL(s) {}", unManagedCifsShareACLList.size());
_dbClient.createObject(unManagedCifsShareACLList);
}
if (!oldunManagedCifsShareACLList.isEmpty()) {
_logger.info("Saving Number of Old UnManagedCifsShareACL(s) {}", oldunManagedCifsShareACLList.size());
_dbClient.persistObject(oldunManagedCifsShareACLList);
}
storageSystem.setDiscoveryStatus(DiscoveredDataObject.DataCollectionJobStatus.COMPLETE.toString());
// discovery succeeds
detailedStatusMessage = String.format("Discovery completed successfully for NetApp: %s", systemId.toString());
} catch (NetAppException ve) {
if (null != storageSystem) {
cleanupDiscovery(storageSystem);
storageSystem.setDiscoveryStatus(DiscoveredDataObject.DataCollectionJobStatus.ERROR.toString());
}
_logger.error("discoverStorage failed. Storage system: " + systemId);
} catch (Exception e) {
if (null != storageSystem) {
cleanupDiscovery(storageSystem);
storageSystem.setDiscoveryStatus(DiscoveredDataObject.DataCollectionJobStatus.ERROR.toString());
}
_logger.error("discoverStorage failed. Storage system: " + systemId, e);
} finally {
if (storageSystem != null) {
try {
// set detailed message
storageSystem.setLastDiscoveryStatusMessage(detailedStatusMessage);
_dbClient.persistObject(storageSystem);
} catch (Exception ex) {
_logger.error("Error while persisting object to DB", ex);
}
}
}
}
Aggregations