javagoogle-cloud-platformvirtual-machinegoogle-compute-enginegoogle-compute-api

Suspend Google Cloud Platform instance using Java


I have a Java web application in which I create GCP VM instances and perform operations on them.

I use the Java Compute Engine API to perform tasks such as creation, start, stop etc.

I wanted to perfrom:

Compute compute = getComputeObj();
Suspend suspend = compute.instances().suspend(getProjectId(), getOrder().getAvailabilityZone(), getOrder().getMachineName());
Operation response = suspend .execute();

However, I cannot "Suspend" a machine with this API as "Suspend" is in beta version (it is not part of the Compute Engine v1 API so it is not part of the Java wrapper).

As I see it I have two options to solve this problem, neither of which I have been able to complete:

  1. Create a Java class "ComputeBeta" which inherits the Compute class and implement a Suspend class to execute the operation. This is problematic as the URL field in the original Compute class is a final field, so I can not change the URL from the "v1" to the "beta" url.

  2. Execute a "regular" httpconnection to the GCP beta API in order to suspend the machine. The problem here is that I have not been able to find the correct syntax of the authentication to the API and have been getting a 401 response. What I have tried so far:

String serviceAccountKey = getServiceAccountKey();

String baseUrl = "https://compute.googleapis.com";

String endpoint = "/compute/beta/projects/" + getOrder().getProject() 
                + "/zones/" + getOrder().getAvailabilityZone() + "/instances/" 
                + getOrder().getMachineName() + "/suspend";

URL serverUrl = new URL(baseUrl + endpoint);

httpConnection = (HttpsURLConnection)serverUrl.openConnection();
httpConnection.setRequestMethod(HttpMethods.POST);
httpConnection.setDoOutput(true);
httpConnection.setDoInput(true);


httpConnection.setFixedLengthStreamingMode(length);

httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpConnection.setRequestProperty("Authorization", "Bearer " + serviceAccountKey);
httpConnection.connect();

int responseCode = httpConnection.getResponseCode();
String responseMessage = httpConnection.getResponseMessage();

Any assistance on how to move forward will be greatly appreciated!


Solution

  • You don't have to use your service account key like this. This key allow you to create a credential and then to generate token with it.

     GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
    // You can use explicitly your service account key file like this
    // GoogleCredentials credentials = GoogleCredentials.fromStream(this.getClass().getResourceAsStream("my_key_file.json"));
    
     String token = credentials.refreshAccessToken().getTokenValue();
    ...
     httpConnection.setRequestProperty("Authorization", "Bearer " + token);
    
    

    You can also use the Google Transport factory to avoid to add manually the authorization header

     GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
    // You can use explicitly your service account key file like this
    // GoogleCredentials credentials = GoogleCredentials.fromStream(this.getClass().getResourceAsStream("my_key_file.json"));
    
    HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(credentials));
    // Here a GET request, but you can build a POST request also
    HttpRequest request = factory.buildGetRequest(new GenericUrl("YOUR_URL"));
    HttpResponse httpResponse = request.execute();
    System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
    

    If you have dependency issue (normally not because you use the compute engine library that include it), you can add this dependency

            <dependency>
                <groupId>com.google.auth</groupId>
                <artifactId>google-auth-library-oauth2-http</artifactId>
                <version>0.21.1</version>
            </dependency>