Skip to content

Create Scratch Vapp Example

Nick Kasprzak edited this page Mar 29, 2019 · 13 revisions

Introduction

This is a guide to take you through building your own project from scratch, building a from scratch vApp through iland's Java SDK, doing power operations on it's VM and then deleting it.

Understanding the basics of Java is not a required skill but preferable. If you might need a refresher on the language, check out this link If you don't want to build everything from scratch you can just git clone the project and follow along with the tutorial without having to write everything yourself.

To get this example app use this code:

git clone https://github.com/ilanddev/java-sdk.git

And then cd into the create-scratch-vapp example.

Required software

The first step in order to setup the project is making sure Java and Maven are installed.

To check if you have Java installed, run this command in the terminal:

$ java -version

If you need to install Java follow this guide. Follow this guide for installing Maven.

Verify that you have installed Maven with this command:

$ mvn -v

Once you have installed Maven and Java we can begin building the app.

Initial setup

To build a basic Java project with maven you run this command:

$ mvn archetype:generate -DgroupId=com.iland.app -DartifactId=create-scratch-vapp -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

The groupId and artifactId can be whatever you specify. I chose com.iland.app and create-vapp.

We now have a basic Java project with a pom.xml file and a App.java file.

To confirm you have everything working run these commands.

$ cd create-vapp
$ mvn clean install
$ java -jar target/create-scratch-vapp-1.0-SNAPSHOT.jar

This will move you into the project's directory, build the project and then run it.

If everything is working you should see Hello World! in your terminal.

Note: If you used different groupId and artifactId then you will have to change the last command to reflect whatever you values you used.

Editing the pom.xml

To be able to use the iland Java SDK we will have to edit the pom.xml. So open up pom.xml file with a text editor and find the <dependencies> tag and add the following under the existing </dependency> tag.

<dependency>
      <groupId>com.iland.core</groupId>
      <artifactId>iland-sdk</artifactId>
      <version>1.0.0-b1</version>
</dependency>

Once you have done that we need to add the repository that the SDK is located at. So after the </dependencies> tag add the following code.

<repositories>
    <repository>
      <id>iland-sdk-mvn-repo</id>
      <url>https://raw.githubusercontent.com/ilanddev/java-sdk/mvn-repo</url>
      <snapshots>
        <enabled>true</enabled>
        <updatePolicy>always</updatePolicy>
      </snapshots>
    </repository>
  </repositories>

This will tell Maven where to pull iland's Java SDK from. Lastly we need to tell Maven where to execute the Main class. In the plugin section first remove the tags that contain <pluginManagement> and </pluginManagement>. Then add the following code to after the last </plugin> tag or just replace all the plugin section:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
        <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        <configuration>
        <transformers>
            <transformer
                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>com.iland.app.App</mainClass>
            </transformer>
        </transformers>
        /configuration>
    </execution>
    </executions>
</plugin>

Now run mvn clean install again and confirm you can still build successfully.

Authentication

Now that we have the project and the pom.xml correctly configured we can start playing around with the SDK. First open the App.java file which will be found in the lowest directory. Mine is located at /create-scratch-vapp/src/main/java/com/iland/app. If you have used the same groudId and artifactId as me then it will be in the same location. Before we can start making calls to iland's API with the SDK we must first authenticate our user. To do so we must have four following variables:

  • username
  • password
  • client name
  • client secret

You should have a username and password already if you have an account with iland. To get the client secret and client name you must email support@iland.com for these credentials. So in the App.java before the public static void main(String[] args) function add the following code:

final static String USERNAME = "";
final static String PASSWORD = "";
final static String CLIENT_NAME ="";
final static String CLIENT_SECRET = "";

Fill in these variables with your own credentials. Now we will sign in so we can use the API. The first thing we need to is create a Client from our SDK. Below the variables you just created add the following code:

static Client apiClient = new Client(CLIENT_NAME, CLIENT_SECRET);  

This will create a client with which we can login into the API and call the resources we need. Note: I am using an IDE which automatically adds the needed imports to my code. If you are just using a basic text editor you will have to import everything yourself. For example the Client object I just added needs the following line of code import com.iland.core.web.sdk.Client; at the beginning of the App.java file. You will not be able to compile the project without the proper imports. Go to the Common Problems to see how to fix import issues. Now we need to login. The following code is how you login. Add this into the main function or your own function.

try {
    apiClient.login(USERNAME, PASSWORD);
} catch (final OAuthException e) {
    System.out.println(e.getMessage());
}

The login() function can throw a OAuthException thus the need to wrap it in a try/catch block. At the end of your code be sure to apiClient.logout()

Creating vApps and VMs

So now that we have successfully logged into the API we can start using the SDK. iland's API is divided into various resources that we can call to do various tasks. In this example we are trying to create a virtual machine so we will need to use the resources that allow us to do that. Here is the link to our documentation that shows all the resources we can use with the SDK. For this example we will need these resources:

  • UserResource
  • VdcResource
  • TaskResource

To instantiate an API resource is easy with the Client we created earlier. All you need to do is this:

UserResource userResource = apiClient.getUserResource();
VdcResource vappResource = apiClient.getVdcResource();
TaskResource taskResouce = apiClient.getTaskResource();

Now we can use the functions in these resource objects to create a vApp. To create a vApp either from scratch of from an existing vapp template we must use the VdcResource. Within the VdcResource we have either the option of using the functions addVappFromTemplate or buildVapp. To find what functions VdcResource has look in the documentation here. Let's use buildVapp to build a vApp from scratch. Looking at buildVapp parameters we see that it takes a String called vdcUuid and a BuildVappRequest object called spec. Now how do you know what the vdcUuid is? Or better question which ones you have permissions to use? Well in UserResource we have a function called getInventory(). It takes two parameters, the username and the companyId. If you don't specify the companydId then it will get all the inventory the user has permission for every company that user belongs to. So let's the get the user's inventory with the following code:

UserInventoryResponse userInventory = userResource.getInventory(USERNAME, null);

This returns an object called UserInventoryResponse, if we look at the documentation for this object here we can see that the response object has a list of objects called UserCompanyInventoryResponse. These objects represent each company the user has permissions to and within them is a Map of IamEntityType to a list of UserInventoryEntityResponse. So by iterating through the UserCompanyInventoryResponse objects we can find the vDCs the user has permission to and print out their UUIDs and names. Here's how to do that:

for (UserCompanyInventoryResponse companyInventory : userInventory.getInventory()) {
    if(copmanyInventory.getEntities() != null && !copmanyInventory.getEntities().isEmpty()) {
        List<UserInventoryEntityResponse> vDCS = companyInventory.getEntities().get(IamEntityType.IAAS_VDC);
        for (UserInventoryEntityResponse vDC : vDCS) {
             System.out.println(String.format("vDC name: %s, UUID: %s", vDC.getName(), vDC.getUuid()));
        }
    }
}

If you build the project and run the java -jar command from earlier, you will print out all the vDC names and uuids your user has permission for. Instead of printing all of them out, let's just grab one so we can use it to create a vApp. Declare a String vdcUuid = ""; outside of the for loops and replace the System.out.println() with the following code:

vdcUuid = vDC.getUuid();
break;

Now we have a vDC uuid, let's look at the BuildVappRequest spec parameter. Looking at the documentation here, we see that the BuildVappRequest object takes a String name, a String description and a List of BuildVmRequest called vms. We can build a very basic vAppp with no VMs with the following code.

BuildVappRequest vappRequest = new BuildVappRequest("vapp_name", "vapp_description", Collections.emptyList());
TaskResponse taskResponse = vdcResource.buildVapp(TestVDCs.PAYG, vappRequest);

This code creates a bare bones vApp in the vDC with no VMs. It just has the name and description you provide. The function buildVapp returns a TaskResponse that I will address later. Note: vApp names must be unique. You will get an error if you try making a vApp with the same name as an existing vApp. To build a vApp that has VMs we must the BuildVmRequest object. From the documentation of BuildVmRequest here we can see the constructor of BuildVmRequest is the following:

BuildVmRequest(String name, String description, String vmTemplateUuid, String vappTemplateUuid, List<VmDiskRequest> disks, Integer ram, Integer numberOfCpus, Integer cpuCoresPerSocket, Integer hardwareVersion, String operatingSystemVersion, Integer bootDelay, Boolean exposeCpuVirtualization, String mediaUuid, String computerName, String storageProfileUuid, List<VmVnicRequest> vnics) 

So in our code when we want to build a VM from scratch we must fill in the parameters we need for BuildVmRequest, put it into an ArrayList and pass it in buildVapp(). With the BuildVmRequest there are countless ways to customize the VMs you want to create. Here's an example of a basic VM you can create:

String vmName = "Example Scratch Vapp";
String vmDescription = "vApp's description";
Integer ram = 2000;
Integer numOfCpus = 4;
Integer cpuCoresPerSocket = 2;
Integer hardwareVersion = 11;
String operatingSystem = "ubuntu64Guest";
Integer bootDelay = 0;
boolean exposeCpuVirtualization = true;
final BuildVmRequest scratchVm =
        new BuildVmRequest(vmName, vmDescription, null, null, Collections.emptyList(), ram,
            numOfCpus, cpuCoresPerSocket, hardwareVersion, operatingSystem, bootDelay,
            exposeCpuVirtualization, null, "testComName", null, Collections.emptyList());

This creates a basic Ubuntu VM with the specific details that I specified in the spec. Note: All of the fields I included for the scratch VM are required. If you don't provide any of these you will get an error back from our API that they are required. If you want to figure out which operating systems and what to pass for them look at ConstantsResource function getOperatingSystems.

Handling tasks

As you can tell from the code, the buildVapp endpoint returns something called a TaskResponse. A TaskResponse represents the task that tracks the progress of whatever you called from the API, in this case it tracks the creation of the vApp. The TaskResponse is very useful because it contains information like the progress of the task, whether the task succeeded and messages of errors that might have occurred. We will write a function that helps just check whether or not the task has been synced by querying the TaskResource for a given interval.

private static void waitForSyncedTask(final String taskUuid) {
    boolean synced = false;
    TaskResponse coreTask;
    while (!synced) {
      try {
        // Thread sleep takes time in milliseconds, here we wait 2 seconds before checking to see if the task has synced yet. 
        Thread.sleep(2000);
      } catch (final InterruptedException e) {
        System.out.println(String.format("Error while waiting for task=%s. %s",taskUuid, e.getMessage()));
      }
      coreTask = taskResource.getTask(taskUuid);
      synced = coreTask.isSynced();
    }
}

So now that the task is synced we can get it again and check if it succeeded by using the following code:

TaskResponse syncedBuildVappTask = taskResource.getTask(buildVappTask.getUuid());
    if (syncedBuildVappTask.getStatus().equals("ERROR")) {
      System.out.println(syncedBuildVappTask.getMessage());
    }

If nothing is printed we know that the vApp and VM have been created successfully.

VM power operations

Powering on and off a VM is as easy as a few lines of code. To do this we need the VM uuid of the VM we want to power on/off. Since we have the name of the vApp we just created we can find the uuid of the vApp by getting all the vApps from the vDC, checking the names, and getting the uuid for our newly created vApp. This method of finding what a vApp's uuid is based on it's name works because vApp's name are unique. You will find this out yourself if you try to create a vApp with the same exact name as an existing one as iland's API will not allow you to.

VappListResponse vapps = vdcResource.getVapps(vdcUuid);
String vappUuid = "";
for (VappResponse vapp : vapps) {
    if(vapp.getName().equals(vappName)) {
        vappUuid = vapp.getUuid();
        break;
    }
}

So now that we have the vApp we created we can find the uuid of it's VM. We can do that we the following code:

VappResource vappResource = apiClient.getVappResource();
VmListResponse vms = vappResource.getVms(vappUuid);
VmResponse vm = vms.getData().get(0);

Now that we have the VmResponse object of the scratch VM we just made we can now do power operations on it. Power operations with iland's Java SDK are as easy as this:

TaskResponse startVm = vmResource.powerOnVm(vm.getUuid(), false);
TaskResponse stopVm = vmResource.powerOffVm(vm.getUuid());

Remember to declare a TaskResponse when calling powerOn and powerOff so you can track when the task is synced and thus the power state of your VM.

Deleting vApps

Deleting vApps much easier than creating them. All you need is the UUID of what you want to delete and the permissions to delete them. Here is an example of how to delete a vApp.

vappResource.deleteVapp(vappUuid)

Logging out

When you are done using iland's Java SDK it is time to logout. In the main function use this code to logout for the Client

apiClient.logout()

Tips

Declaring resources every time you need to use them is tedious and repetitive. If you know which resources you want to use, you should declare them globally and then instatiate them once so you can re-use them in whatever functions you may creating. Remember to track whatever you do with TaskResponse and make sure the tasks are synced before preforming multiple operations on any resource.

Important Links

iland's API Swagger docs iland's Java SDK docs

Common Problems

Here I will address common problems that you might face when trying to use iland's Java SDK.

Missing Imports

If you don't have all the nescessary imports you might see an error like this

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project my-app: Compilation failure: Compilation failure: 
[ERROR] /home/user/code/create-vm/my-app/src/main/java/com/mycompany/app/App.java:[36,10] cannot find symbol
[ERROR]   symbol:   class Client
[ERROR]   location: class com.mycompany.app.App

As you can see Maven cannot find the class Client because we have not included the correct imports. To find the correct package to use in your import you can use this custom Google search engine here to search the Java SDK docs. After finding the resource or object you need to import look near the top of the page on the left hand side and you should see something like com.iland.core.web.sdk.Client. Add that to the top of your Java file and re-compile the code to see if that fixes your import error.

Clone this wiki locally