| /* |
| * 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.apache.brooklyn.launcher.command.support; |
| |
| import java.io.InputStream; |
| import java.io.PrintStream; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.Callable; |
| |
| import org.apache.brooklyn.api.location.Location; |
| import org.apache.brooklyn.api.location.LocationDefinition; |
| import org.apache.brooklyn.api.mgmt.ManagementContext; |
| import org.apache.brooklyn.location.jclouds.BlobStoreContextFactoryImpl; |
| import org.apache.brooklyn.location.jclouds.JcloudsLocation; |
| import org.apache.brooklyn.location.jclouds.JcloudsLocationCustomizer; |
| import org.apache.brooklyn.location.jclouds.LocationCustomizerDelegate; |
| import org.apache.brooklyn.util.core.config.ConfigBag; |
| import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException; |
| import org.apache.brooklyn.util.stream.Streams; |
| import org.jclouds.blobstore.BlobStore; |
| import org.jclouds.blobstore.BlobStoreContext; |
| import org.jclouds.blobstore.domain.Blob; |
| import org.jclouds.blobstore.domain.StorageMetadata; |
| import org.jclouds.compute.ComputeService; |
| import org.jclouds.compute.domain.ComputeMetadata; |
| import org.jclouds.compute.domain.Hardware; |
| import org.jclouds.compute.domain.Image; |
| import org.jclouds.compute.domain.NodeMetadata; |
| import org.jclouds.compute.domain.Template; |
| import org.jclouds.compute.options.TemplateOptions; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Objects; |
| import com.google.common.collect.Lists; |
| |
| /** |
| * Convenience for listing Cloud Compute and BlobStore details. |
| * <p> |
| * For fuller functionality, consider instead the jclouds CLI or Ruby Fog CLI. |
| * <p> |
| * The advantage of this utility is that it piggie-backs off the {@code brooklyn.property} credentials, |
| * so requires less additional credential configuration. It also gives brooklyn-specific information, |
| * such as which image will be used by default in a given cloud. |
| */ |
| public abstract class CloudExplorerSupport implements Callable<Void> { |
| |
| private ManagementContext managementContext; |
| |
| public static final String ALL_LOCATIONS_DESC = |
| "All locations (i.e. all locations in brooklyn.properties for which there are credentials)"; |
| public boolean allLocations; |
| |
| public static final String LOCATION_DESC = |
| "A location spec (e.g. referring to a named location in brooklyn.properties file)"; |
| public String location; |
| |
| public static final String AUTOCONFIRM_DESC = "Automatically answer yes to any questions"; |
| public boolean autoconfirm = false; |
| |
| |
| @VisibleForTesting |
| protected PrintStream stdout = System.out; |
| |
| @VisibleForTesting |
| protected PrintStream stderr = System.err; |
| |
| @VisibleForTesting |
| protected InputStream stdin = System.in; |
| |
| public CloudExplorerSupport(ManagementContext managementContext, boolean allLocations, String location, boolean autoconfirm) { |
| this.managementContext = managementContext; |
| this.allLocations = allLocations; |
| this.location = location; |
| this.autoconfirm = autoconfirm; |
| } |
| |
| protected abstract void doCall(JcloudsLocation loc, String indent) throws Exception; |
| |
| @Override |
| public Void call() throws Exception { |
| List<JcloudsLocation> locs = Lists.newArrayList(); |
| if (location != null && allLocations) { |
| throw new FatalConfigurationRuntimeException("Must not specify --location and --all-locations"); |
| } else if (location != null) { |
| JcloudsLocation loc = (JcloudsLocation) managementContext.getLocationRegistry().getLocationManaged(location); |
| locs.add(loc); |
| } else if (allLocations) { |
| // Find all named locations that point at different target clouds |
| Map<String, LocationDefinition> definedLocations = managementContext.getLocationRegistry().getDefinedLocations(true); |
| for (LocationDefinition locationDef : definedLocations.values()) { |
| |
| Location loc = managementContext.getLocationManager().createLocation( |
| managementContext.getLocationRegistry().getLocationSpec(locationDef).get() ); |
| |
| if (loc instanceof JcloudsLocation) { |
| boolean found = false; |
| for (JcloudsLocation existing : locs) { |
| if (equalTargets(existing, (JcloudsLocation) loc)) { |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| locs.add((JcloudsLocation) loc); |
| } |
| } |
| } |
| } else { |
| throw new FatalConfigurationRuntimeException("Must specify one of --location or --all-locations"); |
| } |
| |
| // TODO consider using org.apache.karaf.shell.support.table.ShellTable to replace/supplement this formatting, |
| // here and elsewhere in this class |
| for (JcloudsLocation loc : locs) { |
| stdout.println("Location {"); |
| stdout.println("\tprovider: "+loc.getProvider()); |
| stdout.println("\tdisplayName: "+loc.getDisplayName()); |
| stdout.println("\tidentity: "+loc.getIdentity()); |
| if (loc.getEndpoint() != null) stdout.println("\tendpoint: "+loc.getEndpoint()); |
| if (loc.getRegion() != null) stdout.println("\tregion: "+loc.getRegion()); |
| |
| try { |
| doCall(loc, "\t"); |
| } finally { |
| stdout.println("}"); |
| } |
| } |
| |
| return null; |
| } |
| |
| protected boolean equalTargets(JcloudsLocation loc1, JcloudsLocation loc2) { |
| return Objects.equal(loc1.getProvider(), loc2.getProvider()) |
| && Objects.equal(loc1.getIdentity(), loc2.getIdentity()) |
| && Objects.equal(loc1.getEndpoint(), loc2.getEndpoint()) |
| && Objects.equal(loc1.getRegion(), loc2.getRegion()); |
| } |
| |
| |
| public static abstract class ComputeExploration extends CloudExplorerSupport { |
| protected abstract void doCall(ComputeService computeService, String indent) throws Exception; |
| |
| public ComputeExploration(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm) { |
| super(managementContext, allLocations, location, autoconfirm); |
| } |
| |
| @Override |
| protected void doCall(JcloudsLocation loc, String indent) throws Exception { |
| ComputeService computeService = loc.getComputeService(); |
| doCall(computeService, indent); |
| } |
| } |
| |
| public static class ListInstances extends ComputeExploration { |
| public static final String NAME = "list-instances"; |
| public static final String DESCRIPTION = "list instances"; |
| |
| public ListInstances(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm) { |
| super(managementContext, allLocations, location, autoconfirm); |
| } |
| |
| @Override |
| protected void doCall(ComputeService computeService, String indent) throws Exception { |
| Set<? extends ComputeMetadata> instances = computeService.listNodes(); |
| stdout.println(indent+"Instances {"); |
| for (ComputeMetadata instance : instances) { |
| stdout.println(indent+"\t"+instance); |
| } |
| stdout.println(indent+"}"); |
| } |
| } |
| |
| public static class ListImages extends ComputeExploration { |
| public static final String NAME = "list-images"; |
| public static final String DESCRIPTION = "list images"; |
| |
| public ListImages(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm) { |
| super(managementContext, allLocations, location, autoconfirm); |
| } |
| |
| @Override |
| protected void doCall(ComputeService computeService, String indent) throws Exception { |
| Set<? extends Image> images = computeService.listImages(); |
| stdout.println(indent+"Images {"); |
| for (Image image : images) { |
| stdout.println(indent+"\t"+image); |
| } |
| stdout.println(indent+"}"); |
| } |
| } |
| |
| public static class ListHardwareProfiles extends ComputeExploration { |
| public static final String NAME = "list-hardware-profiles"; |
| public static final String DESCRIPTION = "list hardware profiles"; |
| |
| public ListHardwareProfiles(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm) { |
| super(managementContext, allLocations, location, autoconfirm); |
| } |
| |
| @Override |
| protected void doCall(ComputeService computeService, String indent) throws Exception { |
| Set<? extends Hardware> hardware = computeService.listHardwareProfiles(); |
| stdout.println(indent+"Hardware Profiles {"); |
| for (Hardware image : hardware) { |
| stdout.println(indent+"\t"+image); |
| } |
| stdout.println(indent+"}"); |
| } |
| } |
| |
| public static class GetImage extends ComputeExploration { |
| public static final String NAME = "get-image"; |
| public static final String DESCRIPTION = "get image details for one or more imageIds"; |
| public static final String ARGUMENT_NAME = "imageIds"; |
| public static final String ARGUMENT_DESC = "IDs of the images to retrieve"; |
| |
| private List<String> names; |
| |
| public GetImage(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm, List<String> arguments) { |
| super(managementContext, allLocations, location, autoconfirm); |
| names = arguments; |
| } |
| |
| @Override |
| protected void doCall(ComputeService computeService, String indent) throws Exception { |
| |
| for (String imageId : names) { |
| Image image = computeService.getImage(imageId); |
| if (image == null) { |
| return; |
| } |
| stdout.println(indent+"Image "+imageId+" {"); |
| stdout.println(indent+"\t"+image); |
| stdout.println(indent+"}"); |
| } |
| } |
| } |
| |
| public static class ComputeDefaultTemplate extends CloudExplorerSupport { |
| public static final String NAME = "default-template"; |
| public static final String DESCRIPTION = "compute default template"; |
| |
| public ComputeDefaultTemplate(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm) { |
| super(managementContext, allLocations, location, autoconfirm); |
| } |
| |
| @Override |
| protected void doCall(JcloudsLocation loc, String indent) throws Exception { |
| |
| ComputeService computeService = loc.getComputeService(); |
| ConfigBag setup = loc.config().getBag(); |
| |
| JcloudsLocationCustomizer customizersDelegate = LocationCustomizerDelegate.newInstance(loc.getManagementContext(), setup); |
| Template template = loc.buildTemplate(computeService, setup, customizersDelegate); |
| Image image = template.getImage(); |
| Hardware hardware = template.getHardware(); |
| org.jclouds.domain.Location location = template.getLocation(); |
| TemplateOptions options = template.getOptions(); |
| stdout.println(indent+"Default template {"); |
| stdout.println(indent+"\tImage: "+image); |
| stdout.println(indent+"\tHardware: "+hardware); |
| stdout.println(indent+"\tLocation: "+location); |
| stdout.println(indent+"\tOptions: "+options); |
| stdout.println(indent+"}"); |
| } |
| } |
| |
| public static class TerminateInstances extends ComputeExploration { |
| public static final String NAME = "terminate-instances"; |
| public static final String DESCRIPTION = "terminate instances for one or more instance IDs"; |
| public static final String ARGUMENT_NAME = "instanceIds"; |
| public static final String ARGUMENT_DESC = "IDs of the instances to terminate"; |
| private List<String> names; |
| |
| public TerminateInstances(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm, List<String> names) { |
| super(managementContext, allLocations, location, autoconfirm); |
| this.names = names; |
| } |
| |
| @Override |
| protected void doCall(ComputeService computeService, String indent) throws Exception { |
| |
| for (String instanceId : names) { |
| NodeMetadata instance = computeService.getNodeMetadata(instanceId); |
| if (instance == null) { |
| stderr.println(indent+"Cannot terminate instance; could not find "+instanceId); |
| } else { |
| boolean confirmed = confirm(indent, "terminate "+instanceId+" ("+instance+")"); |
| if (confirmed) { |
| computeService.destroyNode(instanceId); |
| } |
| } |
| } |
| } |
| } |
| |
| public static abstract class Blobstore extends CloudExplorerSupport { |
| public Blobstore(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm) { |
| super(managementContext, allLocations, location, autoconfirm); |
| } |
| |
| protected abstract void doCall(org.jclouds.blobstore.BlobStore blobstore, String indent) throws Exception; |
| |
| @Override |
| protected void doCall(JcloudsLocation loc, String indent) throws Exception { |
| BlobStoreContext context = BlobStoreContextFactoryImpl.INSTANCE.newBlobStoreContext(loc); |
| try { |
| org.jclouds.blobstore.BlobStore blobStore = context.getBlobStore(); |
| doCall(blobStore, indent); |
| } finally { |
| context.close(); |
| } |
| } |
| } |
| |
| public static class BlobstoreListContainers extends Blobstore { |
| public static final String NAME = "list-containers"; |
| public static final String DESCRIPTION = "list containers"; |
| |
| public BlobstoreListContainers(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm) { |
| super(managementContext, allLocations, location, autoconfirm); |
| } |
| |
| @Override |
| protected void doCall(BlobStore blobstore, String indent) throws Exception { |
| Set<? extends StorageMetadata> containers = blobstore.list(); |
| stdout.println(indent+"Containers {"); |
| for (StorageMetadata container : containers) { |
| stdout.println(indent+"\t"+container); |
| } |
| stdout.println(indent+"}"); |
| } |
| } |
| |
| public static class BlobstoreListContainer extends Blobstore { |
| public static final String NAME = "list-container"; |
| public static final String DESCRIPTION = "list container details for one or more container names"; |
| public static final String ARGUMENT_NAME = "container-names"; |
| public static final String ARGUMENT_DESC = "names of the containers to list"; |
| private List<String> names; |
| |
| public BlobstoreListContainer(ManagementContext managementContext, boolean allLocations, String location, |
| boolean autoconfirm, List<String> names) { |
| super(managementContext, allLocations, location, autoconfirm); |
| this.names = names; |
| } |
| |
| @Override |
| protected void doCall(BlobStore blobStore, String indent) throws Exception { |
| for (String containerName : names) { |
| Set<? extends StorageMetadata> contents = blobStore.list(containerName); |
| stdout.println(indent+"Container "+containerName+" {"); |
| for (StorageMetadata content : contents) { |
| stdout.println(indent+"\t"+content); |
| } |
| stdout.println(indent+"}"); |
| } |
| } |
| } |
| |
| public static class GetBlob extends Blobstore { |
| public static final String NAME = "blob"; |
| public static final String DESCRIPTION = "list blob details for a given container and blob"; |
| public static final String CONTAINER_ARGUMENT_NAME = "--container"; |
| public static final String CONTAINER_ARGUMENT_DESC = "name of the container of the blob"; |
| public static final String BLOB_ARGUMENT_NAME = "--blob"; |
| public static final String BLOB_ARGUMENT_DESC = "name of the blob in the container"; |
| public String container; |
| public String blob; |
| |
| public GetBlob(ManagementContext managementContext, boolean allLocations, String location, boolean autoconfirm, |
| String container, String blob) { |
| super(managementContext, allLocations, location, autoconfirm); |
| this.container = container; |
| this.blob = blob; |
| } |
| |
| @Override |
| protected void doCall(BlobStore blobStore, String indent) throws Exception { |
| Blob content = blobStore.getBlob(container, blob); |
| stdout.println(indent+"Blob "+container+" : " +blob +" {"); |
| stdout.println(indent+"\tHeaders {"); |
| for (Map.Entry<String, String> entry : content.getAllHeaders().entries()) { |
| stdout.println(indent+"\t\t"+entry.getKey() + " = " + entry.getValue()); |
| } |
| stdout.println(indent+"\t}"); |
| stdout.println(indent+"\tmetadata : "+content.getMetadata()); |
| stdout.println(indent+"\tpayload : "+ Streams.readFullyStringAndClose(content.getPayload().openStream())); |
| stdout.println(indent+"}"); |
| } |
| } |
| |
| protected boolean confirm(String msg, String indent) throws Exception { |
| if (autoconfirm) { |
| stdout.println(indent+"Auto-confirmed: "+msg); |
| return true; |
| } else { |
| stdout.println(indent+"Enter y/n. Are you sure you want to "+msg); |
| int in = stdin.read(); |
| boolean confirmed = (Character.toLowerCase(in) == 'y'); |
| if (confirmed) { |
| stdout.println(indent+"Confirmed; will "+msg); |
| } else { |
| stdout.println(indent+"Declined; will not "+msg); |
| } |
| return confirmed; |
| } |
| } |
| } |