Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2022 Google LLC
//
// 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.

package compute.windows.osimage;

// [START compute_windows_image_create]

import com.google.cloud.compute.v1.Disk;
import com.google.cloud.compute.v1.DisksClient;
import com.google.cloud.compute.v1.Image;
import com.google.cloud.compute.v1.ImagesClient;
import com.google.cloud.compute.v1.InsertImageRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.Operation;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

public class CreateWindowsOsImage {

public static void main(String[] args)
throws IOException, ExecutionException, InterruptedException {
// TODO(developer): Replace these variables before running the sample.

// Project ID or project number of the Cloud project you use.
String project = "your-project-id";
// Zone of the disk you copy from.
String zone = "europe-central2-b";
// Name of the source disk you copy from.
String sourceDiskName = "source-disk-name";
// Name of the image you want to create.
String imageName = "your-image-name";
// Storage location for the image. If the value is undefined,
// function will store the image in the multi-region closest to your image's source location.
String storageLocation = "eu";
// Create the image even if the source disk is attached to a running instance.
boolean forceCreate = false;

createWindowsOsImage(project, zone, sourceDiskName, imageName, storageLocation, forceCreate);
}

// Creates a new Windows image from the specified source disk.
public static void createWindowsOsImage(String project, String zone, String sourceDiskName,
String imageName, String storageLocation, boolean forceCreate)
throws IOException, ExecutionException, InterruptedException {

try (ImagesClient imagesClient = ImagesClient.create();
InstancesClient instancesClient = InstancesClient.create();
DisksClient disksClient = DisksClient.create()) {

Disk disk = disksClient.get(project, zone, sourceDiskName);

// Getting instances where source disk is attached.
for (String fullInstanceName : disk.getUsersList()) {
Map<String, String> instanceInfo = parseInstanceName(fullInstanceName);
Instance instance = instancesClient.get(instanceInfo.get("instanceProjectId"),
instanceInfo.get("instanceZone"), instanceInfo.get("instanceName"));

// Сhecking whether the instances is stopped.
if (!Arrays.asList("TERMINATED", "STOPPED").contains(instance.getStatus())
&& !forceCreate) {
throw new IllegalStateException(
String.format(
"Instance %s should be stopped. Please stop the instance using GCESysprep command or set forceCreate parameter to true (not recommended). More information here: https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api.",
instanceInfo.get("instanceName")));
}
}

if (forceCreate) {
System.out.println(
"Warning: forceCreate option compromise the integrity of your image. "
+ "Stop the instance before you create the image if possible.");
}

// Create Image.
Image image = Image.newBuilder()
.setName(imageName)
.setSourceDisk(String.format("/zones/%s/disks/%s", zone, sourceDiskName))
.addStorageLocations(storageLocation.isEmpty() ? "" : storageLocation)
.build();

InsertImageRequest insertImageRequest = InsertImageRequest.newBuilder()
.setProject(project)
.setForceCreate(forceCreate)
.setImageResource(image)
.build();

Operation response = imagesClient.insertAsync(insertImageRequest).get();

if (response.hasError()) {
System.out.println("Windows OS Image creation failed ! ! " + response);
return;
}

System.out.println("Image created.");
}
}


public static Map<String, String> parseInstanceName(String name) {
String[] parsedName = name.split("/");
int splitLength = parsedName.length;

if (splitLength < 5) {
throw new IllegalArgumentException(
"Provide correct instance name in the following format: "
+ "https://www.googleapis.com/compute/v1/projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME");
}

return new HashMap<>() {
{
put("instanceName", parsedName[splitLength - 1]);
put("instanceZone", parsedName[splitLength - 3]);
put("instanceProjectId", parsedName[splitLength - 5]);
}
};
}

}
// [END compute_windows_image_create]
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Copyright 2022 Google LLC
//
// 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.

package compute.windows.osimage;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.ImagesClient;
import com.google.cloud.compute.v1.InsertInstanceRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import com.google.cloud.compute.v1.Operation;
import compute.DeleteInstance;
import compute.Util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class WindowsOsImageIT {

private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT");
private static final String ZONE = "us-central1-a";
private static String INSTANCE_NAME;
private static String DISK_NAME;
private static String IMAGE_NAME;
@Rule
public ExpectedException expectedException = ExpectedException.none();
private ByteArrayOutputStream stdOut;

// Check if the required environment variables are set.
public static void requireEnvVar(String envVarName) {
assertWithMessage(String.format("Missing environment variable '%s' ", envVarName))
.that(System.getenv(envVarName)).isNotEmpty();
}

@BeforeClass
public static void setup() throws IOException, ExecutionException, InterruptedException {
final PrintStream out = System.out;
ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(stdOut));

requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS");
requireEnvVar("GOOGLE_CLOUD_PROJECT");

// Cleanup existing test instances.
Util.cleanUpExistingInstances("windowsimage-test-instance-", PROJECT_ID, ZONE);

String randomUUID = UUID.randomUUID().toString().split("-")[0];
INSTANCE_NAME = "windowsimage-test-instance-" + randomUUID;
DISK_NAME = "windowsimage-test-disk-" + randomUUID;
IMAGE_NAME = "windowsimage-test-image-" + randomUUID;

// Create Instance with Windows source image.
try (InstancesClient instancesClient = InstancesClient.create()) {
AttachedDisk attachedDisk = AttachedDisk.newBuilder()
.setDeviceName(DISK_NAME)
.setAutoDelete(true)
.setBoot(true)
.setType(AttachedDisk.Type.PERSISTENT.name())
.setInitializeParams(AttachedDiskInitializeParams.newBuilder()
.setDiskName(DISK_NAME)
.setDiskSizeGb(64)
.setSourceImage(
"projects/windows-cloud/global/images/windows-server-2012-r2-dc-core-v20220314")
.build())
.build();

Instance instance = Instance.newBuilder()
.setName(INSTANCE_NAME)
.setMachineType(String.format("zones/%s/machineTypes/n1-standard-1", ZONE))
.addNetworkInterfaces(NetworkInterface.newBuilder()
.setName("global/networks/default")
.build())
.addDisks(attachedDisk)
.build();

InsertInstanceRequest request = InsertInstanceRequest.newBuilder()
.setProject(PROJECT_ID)
.setZone(ZONE)
.setInstanceResource(instance)
.build();

Operation response = instancesClient.insertAsync(request).get();
Assert.assertFalse(response.hasError());
}

stdOut.close();
System.setOut(out);
}

@AfterClass
public static void cleanUp() throws IOException, ExecutionException, InterruptedException {
final PrintStream out = System.out;
ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(stdOut));

// Delete image.
ImagesClient imagesClient = ImagesClient.create();
Operation operation = imagesClient.deleteAsync(PROJECT_ID, IMAGE_NAME).get();
if (operation.hasError()) {
System.out.println("Image not deleted.");
}

// Delete instance.
DeleteInstance.deleteInstance(PROJECT_ID, ZONE, INSTANCE_NAME);

stdOut.close();
System.setOut(out);
}

@Before
public void beforeEach() {
stdOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(stdOut));
}

@After
public void afterEach() {
stdOut = null;
System.setOut(null);
}


@Test
public void testCreateWindowsImage_failDueToRunningInstance()
throws IOException, ExecutionException, InterruptedException {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(String.format("Instance %s should be stopped.", INSTANCE_NAME));
CreateWindowsOsImage.createWindowsOsImage(
PROJECT_ID, ZONE, DISK_NAME, IMAGE_NAME, "eu", false);
}


@Test
public void testCreateWindowsImage_pass()
throws IOException, ExecutionException, InterruptedException {
CreateWindowsOsImage.createWindowsOsImage(
PROJECT_ID, ZONE, DISK_NAME, IMAGE_NAME, "eu", true);
assertThat(stdOut.toString()).contains("Image created.");
}

}