Java tutorial
/* * 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.jclouds.ec2.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static java.util.concurrent.TimeUnit.SECONDS; import static org.jclouds.util.Predicates2.retry; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReference; import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.LoginCredentials; import org.jclouds.ec2.EC2Api; import org.jclouds.ec2.compute.domain.PasswordDataAndPrivateKey; import org.jclouds.ec2.compute.domain.RegionAndName; import org.jclouds.ec2.domain.KeyPair; import org.jclouds.ec2.domain.PasswordData; import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.ec2.features.WindowsApi; import org.jclouds.javax.annotation.Nullable; import org.jclouds.logging.Logger; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.util.concurrent.Atomics; /** * @author Adrian Cole */ @Singleton public class PasswordCredentialsFromWindowsInstance implements Function<RunningInstance, LoginCredentials> { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; private final ConcurrentMap<RegionAndName, KeyPair> credentialsMap; private final EC2Api ec2Api; private final Function<PasswordDataAndPrivateKey, LoginCredentials> pwDataToLoginCredentials; @Inject protected PasswordCredentialsFromWindowsInstance(ConcurrentMap<RegionAndName, KeyPair> credentialsMap, EC2Api ec2Api, Function<PasswordDataAndPrivateKey, LoginCredentials> pwDataToLoginCredentials) { this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap"); this.ec2Api = checkNotNull(ec2Api, "ec2Api"); this.pwDataToLoginCredentials = checkNotNull(pwDataToLoginCredentials, "pwDataToLoginCredentials"); } @Override public LoginCredentials apply(final RunningInstance instance) { Optional<? extends WindowsApi> windowsOption = ec2Api.getWindowsApiForRegion(instance.getRegion()); checkState(windowsOption.isPresent(), "windows feature not present in region %s", instance.getRegion()); final WindowsApi windowsApi = windowsOption.get(); LoginCredentials credentials = LoginCredentials.builder().user("Administrator").noPrivateKey().build(); String privateKey = getPrivateKeyOrNull(instance); if (privateKey == null) { return credentials; } // The Administrator password will take some time before it is ready - Amazon says // sometimes // 15 minutes. // So we create a predicate that tests if the password is ready, and wrap it in a retryable // predicate. final AtomicReference<PasswordData> data = Atomics.newReference(); Predicate<String> passwordReady = new Predicate<String>() { @Override public boolean apply(@Nullable String s) { if (Strings.isNullOrEmpty(s)) return false; data.set(windowsApi.getPasswordDataForInstance(instance.getId())); if (data.get() == null) return false; return !Strings.isNullOrEmpty(data.get().getPasswordData()); } }; // TODO: parameterize Predicate<String> passwordReadyRetryable = retry(passwordReady, 600, 10, SECONDS); logger.debug(">> awaiting password data for instance(%s/%s)", instance.getRegion(), instance.getId()); if (passwordReadyRetryable.apply(instance.getId())) { credentials = pwDataToLoginCredentials.apply(new PasswordDataAndPrivateKey(data.get(), privateKey)); logger.debug("<< obtained password data for instance(%s/%s)", instance.getRegion(), instance.getId()); } else { logger.debug("<< unable to get password data for instance(%s/%s)", instance.getRegion(), instance.getId()); } return credentials; } @VisibleForTesting String getPrivateKeyOrNull(RunningInstance instance) { KeyPair keyPair = credentialsMap.get(new RegionAndName(instance.getRegion(), instance.getKeyName())); return keyPair != null ? keyPair.getKeyMaterial() : null; } }