/************************************************************************* * (c) Copyright 2017 Hewlett Packard Enterprise Development Company LP * * 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 3 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, see http://www.gnu.org/licenses/. ************************************************************************/ package com.eucalyptus.portal.instanceusage; import com.eucalyptus.auth.Accounts; import com.eucalyptus.compute.common.ResourceTag; import com.eucalyptus.compute.common.RunningInstancesItemType; import com.eucalyptus.portal.awsusage.QueuedEvent; import com.eucalyptus.resources.client.Ec2Client; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; import java.util.AbstractMap.SimpleEntry; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static java.util.stream.Collectors.groupingBy; public enum InstanceLogReaders implements InstanceLogReader { INSTANCE_TYPE { @Override public InstanceLogs.InstanceLogBuilder read(final QueuedEvent event) { final Optional<RunningInstancesItemType> instance = getInstance(event); if (instance.isPresent()) { return prototype(event) .withInstanceType( instance.get().getInstanceType() ); } else { return empty(event); } } }, PLATFORM { @Override public InstanceLogs.InstanceLogBuilder read(final QueuedEvent event) { final Optional<RunningInstancesItemType> optInstance = getInstance(event); if (optInstance.isPresent()) { final RunningInstancesItemType instance = optInstance.get(); String platform = "linux"; if (instance.getPlatform()!=null && !instance.getPlatform().isEmpty()) { platform = instance.getPlatform().toLowerCase(); } return prototype(event) .withPlatform(platform); } else { return empty(event); } } }, AVAILABILITY_ZONE { @Override public InstanceLogs.InstanceLogBuilder read(final QueuedEvent event) { final Optional<RunningInstancesItemType> instance = getInstance(event); if (instance.isPresent()) { return prototype(event) .withAvailabilityZone(instance.get().getPlacement()); } else { return empty(event); } } }, TAG { @Override public InstanceLogs.InstanceLogBuilder read(final QueuedEvent event) { final Optional<RunningInstancesItemType> instance = getInstance(event); if (instance.isPresent()) { InstanceLogs.InstanceLogBuilder builder = prototype(event); for (final ResourceTag tag : instance.get().getTagSet()) { builder = builder.addTag(tag.getKey(), tag.getValue()); } return builder; } else { return empty(event); } } }; private static Optional<RunningInstancesItemType> getInstance(final QueuedEvent event) { final SimpleEntry<String,String> key = new SimpleEntry<>(event.getAccountId(), event.getResourceId()); try { return instanceCache.get(key); } catch(final ExecutionException ex) { return Optional.empty(); } } private static final LoadingCache<SimpleEntry<String, String>, Optional<RunningInstancesItemType>> instanceCache = CacheBuilder.newBuilder() .maximumSize(1000) .expireAfterWrite(3, TimeUnit.MINUTES) .build( new CacheLoader<SimpleEntry<String, String>, Optional<RunningInstancesItemType>>() { @Override public Optional<RunningInstancesItemType> load(final SimpleEntry<String, String> accountInstanceIdPair) throws Exception { try { final String userId = Accounts.lookupPrincipalByAccountNumberAndUsername(accountInstanceIdPair.getKey(), "admin").getUserId(); final List<RunningInstancesItemType> results = Ec2Client.getInstance().describeInstances(userId, Lists.newArrayList(accountInstanceIdPair.getValue())); return results.stream().findAny(); } catch (final Exception ex) { ; } return Optional.empty(); } }); private static InstanceLogs.InstanceLogBuilder prototype(final QueuedEvent evt) { return InstanceLogs.getInstance().newRecord(evt.getAccountId()) .withInstanceId(evt.getResourceId()) .withLogTime( getHour(new Date(System.currentTimeMillis())) ); } private static Date getHour(final Date time) { final Calendar c = Calendar.getInstance(); c.setTime(time); c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); return c.getTime(); } private static InstanceLogs.InstanceLogBuilder empty(final QueuedEvent evt) { return InstanceLogs.getInstance().newRecord(evt.getAccountId()).empty(); } public static List<InstanceLogs.InstanceLogBuilder> readLogs(final List<QueuedEvent> events) { final List<QueuedEvent> uniqueEvents = events.stream() .collect( groupingBy( e -> e.getResourceId() ) ).entrySet().stream() .map(kv -> kv.getValue().get(0)) .collect(Collectors.toList()); // distinct event for instance ID return uniqueEvents.stream() .map ( e -> INSTANCE_TYPE.read(e) .merge(PLATFORM.read(e)) .merge(AVAILABILITY_ZONE.read(e)) .merge(TAG.read(e)) ).collect(Collectors.toList()); } }