/** * Copyright 2013 Technische Universitat Wien (TUW), Distributed SystemsGroup * E184. * This work was partially supported by the European Commission in terms * of the CELAR FP7 project (FP7-ICT-2011-8 #317790). * * Licensed 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. */ /** * Author : Georgiana Copil - e.copil@dsg.tuwien.ac.at */ package at.ac.tuwien.dsg.rSybl.cloudInteractionUnit.enforcementPlugins.googleCompute; import at.ac.tuwien.dsg.rSybl.cloudInteractionUnit.utils.Configuration; import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp; import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.client.util.store.FileDataStoreFactory; import com.google.api.services.compute.Compute; import com.google.api.services.compute.Compute.MachineTypes; import com.google.api.services.compute.ComputeScopes; import com.google.api.services.compute.model.AccessConfig; import com.google.api.services.compute.model.AttachedDisk; import com.google.api.services.compute.model.AttachedDiskInitializeParams; import com.google.api.services.compute.model.Instance; import com.google.api.services.compute.model.Firewall; import com.google.api.services.compute.model.Firewall.Allowed; import com.google.api.services.compute.model.Image; import com.google.api.services.compute.model.ImageList; import com.google.api.services.compute.model.InstanceList; import com.google.api.services.compute.model.MachineType; import com.google.api.services.compute.model.MachineTypeList; import com.google.api.services.compute.model.Metadata; import com.google.api.services.compute.model.NetworkInterface; import com.google.api.services.compute.model.Operation; import com.google.api.services.compute.model.ServiceAccount; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author Georgiana */ public class GoogleConnectionUtils { private FileDataStoreFactory dataStoreFactory; private String projectId; private static HttpTransport httpTransport; private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); private List<String> SCOPES; private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".store/compute_engine_sample"); private String zoneName; private String clientSecretsPath; private Compute compute; private static final String SOURCE_IMAGE_PREFIX = "https://www.googleapis.com/compute/v1/projects/"; private static final String SOURCE_IMAGE_PATH = "debian-cloud/global/images/debian-7-wheezy-v20150710"; private static final String NETWORK_INTERFACE_CONFIG = "ONE_TO_ONE_NAT"; private static final String NETWORK_ACCESS_CONFIG = "External NAT"; private static final long OPERATION_TIMEOUT_MILLIS = 60 * 1000; public GoogleConnectionUtils() { projectId = Configuration.getGoogleProjectID(); zoneName = Configuration.getGoogleZoneName(); clientSecretsPath = Configuration.getGoogleClientSecretsPath(); SCOPES = new ArrayList<String>(); SCOPES.add(ComputeScopes.COMPUTE); SCOPES.add(ComputeScopes.DEVSTORAGE_READ_ONLY); initialize(); } public List<MachineType> getAvailableFlavors() { List<MachineType> types = new ArrayList<MachineType>(); MachineTypes machineTypes = compute.machineTypes(); try { Compute.MachineTypes.List list = machineTypes.list(projectId, zoneName); MachineTypeList machineTypeList = list.execute(); for (MachineType machineType : machineTypeList.getItems()) { types.add(machineType); // System.out.println("Machine type for "+projectId+" for zone "+zoneName+" : "+machineType.getName()); } } catch (IOException ex) { Logger.getLogger(GoogleConnectionUtils.class.getName()).log(Level.SEVERE, null, ex); } return types; } public String startInstance(String instanceName, String image, String pathToScript, HashMap<String, String> metadata) throws IOException { // Select a machine type. Instance instance = new Instance(); String machine = "https://www.googleapis.com/compute/v1/projects/" + projectId + "/zones/" + this.zoneName + "/machineTypes/n1-standard-1"; instance.setMachineType(machine); // Get a name from the user. instance.setName(instanceName); // Use the default network. Could select here if needed. NetworkInterface iface; iface = new NetworkInterface(); //iface.setFactory(jsonFactory); iface.setNetwork("https://www.googleapis.com/compute/v1/projects/" + projectId + "/global/networks/default"); List<AccessConfig> configs = new ArrayList<>(); AccessConfig config = new AccessConfig(); config.setType(NETWORK_INTERFACE_CONFIG); config.setName(NETWORK_ACCESS_CONFIG); configs.add(config); iface.setAccessConfigs(configs); instance.setNetworkInterfaces(Collections.singletonList(iface)); Firewall firewall = new Firewall(); firewall.setName(instanceName); Allowed allowedTCP8080 = new Allowed(); allowedTCP8080.setIPProtocol("tcp"); List<String> ports = new ArrayList<String>(); ports.add("80"); ports.add("8080"); ports.add("8280"); ports.add("8180"); ports.add("9610"); allowedTCP8080.setPorts(ports); List<Allowed> allowedPorts = new ArrayList<Allowed>(); allowedPorts.add(allowedTCP8080); firewall.setAllowed(allowedPorts); firewall.setDescription("httpports"); firewall.setNetwork(iface.getNetwork()); List<ServiceAccount> serviceAccount = new ArrayList<ServiceAccount>(); ServiceAccount account = new ServiceAccount(); account.setEmail(Configuration.getGoogleAccount()); account.setScopes(SCOPES); serviceAccount.add(account); instance.setServiceAccounts(serviceAccount); compute.firewalls().insert(instanceName, firewall); //Create the Persistent Disk parameters AttachedDiskInitializeParams diskParamsToInsert = new AttachedDiskInitializeParams(); diskParamsToInsert.setDiskName(instanceName); diskParamsToInsert.setDiskSizeGb(10L); if (image.equals("")) { diskParamsToInsert.setSourceImage("https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1404-trusty-v20150909a"); } else { diskParamsToInsert.setSourceImage("projects/" + projectId + "/global/images/" + image); } //Create the disk AttachedDisk diskToInsert = new AttachedDisk(); diskToInsert.setBoot(true); diskToInsert.setType("PERSISTENT"); diskToInsert.setMode("READ_WRITE"); diskToInsert.setInitializeParams(diskParamsToInsert); //Add Disk to List to be added to Instance List<AttachedDisk> listOfDisks = new ArrayList<AttachedDisk>(); listOfDisks.add(diskToInsert); //Add disk to instance instance.setDisks(listOfDisks); Compute.Instances.Insert ins = compute.instances().insert(projectId, zoneName, instance); // Optional - Add a startup script to be used by the VM Instance. if (pathToScript != null && !pathToScript.equalsIgnoreCase("")) { Metadata meta = new Metadata(); Metadata.Items item = new Metadata.Items(); item.setKey("startup-script-url"); if (pathToScript.contains("gs://")) { item.setValue(pathToScript); } else { item.setValue("gs://" + pathToScript); } if (metadata != null) { List<Metadata.Items> items = new ArrayList<Metadata.Items>(); items.add(item); if (Configuration.getSSHKey() != null && !Configuration.getSSHKey().equalsIgnoreCase("")) { String sshKey = readFile(Configuration.getSSHKey()); Metadata.Items sshKeyItem = new Metadata.Items(); sshKeyItem.setKey("sshKeys"); sshKeyItem.setValue(sshKey); } for (String key : metadata.keySet()) { Metadata.Items myItem = new Metadata.Items(); myItem.setKey(key); myItem.setValue(metadata.get(key)); items.add(myItem); } meta.setItems(items); } else { meta.setItems(Collections.singletonList(item)); } instance.setMetadata(meta); } Operation op = ins.execute(); try { op = blockUntilComplete(op, OPERATION_TIMEOUT_MILLIS); } catch (Exception ex) { // RuntimeLogger.logger.info(ex.getMessage()); Logger.getLogger(GoogleConnectionUtils.class.getName()).log(Level.SEVERE, null, ex); } String ip = ""; Compute.Instances.List instances = compute.instances().list(projectId, zoneName); InstanceList list = instances.execute(); if (list != null) { for (Instance inst : list.getItems()) { if (inst.getName().equalsIgnoreCase(instance.getName())) { instance = inst; ip = instance.getNetworkInterfaces().get(0).getNetworkIP(); } } } System.out.println("Operation is " + op.toPrettyString()); System.out.println("The instance is " + ip + instance.toPrettyString()); return ip; } public String readFile(String filename) { String content = null; File file = new File(filename); //for ex foo.txt FileReader reader = null; try { reader = new FileReader(file); char[] chars = new char[(int) file.length()]; reader.read(chars); content = new String(chars); reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException ex) { Logger.getLogger(GoogleConnectionUtils.class.getName()).log(Level.SEVERE, null, ex); } } } return content; } public boolean deleteInstance(String instanceName) throws Exception { System.out.println("================== Deleting Instance " + instanceName + " =================="); Compute.Instances.Delete delete = compute.instances().delete(projectId, zoneName, instanceName); Operation op = delete.execute(); try { op = blockUntilComplete(op, OPERATION_TIMEOUT_MILLIS); } catch (Exception ex) { // RuntimeLogger.logger.info(ex.getMessage()); Logger.getLogger(GoogleConnectionUtils.class.getName()).log(Level.SEVERE, null, ex); return false; } System.out.println("Operation is " + op.toPrettyString()); Compute.Disks.Delete deleteDisk = compute.disks().delete(projectId, zoneName, instanceName); Operation opDisk = deleteDisk.execute(); try { opDisk = blockUntilComplete(opDisk, OPERATION_TIMEOUT_MILLIS); } catch (Exception ex) { // RuntimeLogger.logger.info(ex.getMessage()); Logger.getLogger(GoogleConnectionUtils.class.getName()).log(Level.SEVERE, null, ex); return false; } System.out.println("Operation of disk deletion is " + op.toPrettyString()); return true; } private Credential authorize() { try { GoogleClientSecrets clientSecrets = null; try { FileReader fileReader = new FileReader(new File(clientSecretsPath)); clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, fileReader); } catch (IOException ex) { InputStreamReader streamReader = new InputStreamReader(GoogleComputeAPI.class.getResourceAsStream(clientSecretsPath)); clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, streamReader); Logger.getLogger(GoogleComputeAPI.class.getName()).log(Level.SEVERE, null, ex); } if (clientSecrets.getDetails().getClientId().startsWith("Enter") || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) { System.out.println("Enter Client ID and Secret from https://code.google.com/apis/console/ " + "into compute-engine-cmdline-sample/src/main/resources/client_secrets.json"); System.exit(1); } GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( httpTransport, JSON_FACTORY, clientSecrets, SCOPES).setDataStoreFactory(dataStoreFactory) .build(); return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user"); } catch (IOException ex) { Logger.getLogger(GoogleComputeAPI.class.getName()).log(Level.SEVERE, null, ex); } return null; } public void printInstances() throws IOException { System.out.println("================== Listing Compute Engine Instances =================="); Compute.Instances.List instances = compute.instances().list(projectId, zoneName); InstanceList list = instances.execute(); if (list.getItems() == null) { System.out.println("No instances found. Sign in to the Google APIs Console and create " + "an instance at: code.google.com/apis/console"); } else { for (Instance instance : list.getItems()) { System.err.println(instance.getName()); System.out.println(instance.toPrettyString()); } } } private void initialize() { try { httpTransport = GoogleNetHttpTransport.newTrustedTransport(); dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR); // Authorization Credential credential = authorize(); compute = new Compute.Builder( httpTransport, JSON_FACTORY, null).setApplicationName("app1") .setHttpRequestInitializer(credential).build(); } catch (Exception e) { e.printStackTrace(); // RuntimeLogger.logger.info(e.getMessage()); } } public Operation blockUntilComplete(Operation operation, long timeout) throws Exception { long start = System.currentTimeMillis(); final long POLL_INTERVAL = 5 * 1000; String zone = operation.getZone(); if (zone != null) { String[] bits = zone.split("/"); zone = bits[bits.length - 1]; } String status = operation.getStatus(); String opId = operation.getName(); while (operation != null && !status.equals("DONE")) { Thread.sleep(POLL_INTERVAL); long elapsed = System.currentTimeMillis() - start; if (elapsed >= timeout) { throw new InterruptedException("Timed out waiting for operation to complete"); } if (zone != null) { Compute.ZoneOperations.Get get = compute.zoneOperations().get(this.projectId, this.zoneName, opId); operation = get.execute(); } else { Compute.GlobalOperations.Get get = compute.globalOperations().get(projectId, opId); operation = get.execute(); } if (operation != null) { status = operation.getStatus(); } } return operation; } public List<String> listImages() { List<String> imagesIds = new ArrayList<String>(); try { Compute.Images.List images = compute.images().list(projectId); ImageList imagesList = images.execute(); if (imagesList != null && imagesList.getItems()!=null) { for (Image image : imagesList.getItems()) { imagesIds.add(image.getName()); //System.out.println("Image "+image.getName()); } } } catch (IOException ex) { Logger.getLogger(GoogleConnectionUtils.class.getName()).log(Level.SEVERE, null, ex); } return imagesIds; } }