com.vmware.photon.controller.model.adapters.vsphere.ovf.OvfDeployer.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.photon.controller.model.adapters.vsphere.ovf.OvfDeployer.java

Source

/*
 * Copyright (c) 2015-2016 VMware, Inc. All Rights Reserved.
 *
 * 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 com.vmware.photon.controller.model.adapters.vsphere.ovf;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vmware.photon.controller.model.adapters.vsphere.InstanceClient.ClientException;
import com.vmware.photon.controller.model.adapters.vsphere.VimUtils;
import com.vmware.photon.controller.model.adapters.vsphere.util.connection.BaseHelper;
import com.vmware.photon.controller.model.adapters.vsphere.util.connection.Connection;
import com.vmware.photon.controller.model.adapters.vsphere.util.connection.GetMoRef;
import com.vmware.photon.controller.model.adapters.vsphere.util.finders.FinderException;
import com.vmware.vim25.HttpNfcLeaseDeviceUrl;
import com.vmware.vim25.HttpNfcLeaseInfo;
import com.vmware.vim25.KeyValue;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.OvfCreateImportSpecParams;
import com.vmware.vim25.OvfCreateImportSpecParamsDiskProvisioningType;
import com.vmware.vim25.OvfCreateImportSpecResult;
import com.vmware.vim25.OvfFileItem;
import com.vmware.vim25.OvfNetworkMapping;
import com.vmware.vim25.VirtualMachineConfigSpec;
import com.vmware.vim25.VmConfigSpec;
import com.vmware.xenon.common.Operation;

public class OvfDeployer extends BaseHelper {
    public static final String CONTENT_TYPE_VMDK = "application/x-vnd.vmware-streamVmdk";

    private static final Logger logger = LoggerFactory.getLogger(OvfDeployer.class.getName());
    private static final String PROP_INFO = "info";

    public static final String TRANSPORT_GUESTINFO = "com.vmware.guestInfo";
    public static final String TRANSPORT_ISO = "iso";
    private OvfRetriever ovfRetriever;

    public OvfDeployer(Connection connection) throws ClientException, FinderException {
        super(connection);

        CloseableHttpClient client = OvfRetriever.newInsecureClient();
        this.ovfRetriever = new OvfRetriever(client);
    }

    private long getImportSizeBytes(OvfCreateImportSpecResult importResult) {
        List<OvfFileItem> items = importResult.getFileItem();
        if (items == null) {
            return 0;
        }

        long totalBytes = 0;
        for (OvfFileItem fi : items) {
            totalBytes += fi.getSize();
        }

        return totalBytes;
    }

    public ManagedObjectReference deployOvf(URI ovfUri, ManagedObjectReference host,
            ManagedObjectReference vmFolder, String vmName, List<OvfNetworkMapping> networks,
            ManagedObjectReference datastore, List<KeyValue> ovfProps, String deploymentConfig,
            ManagedObjectReference resourcePool) throws Exception {

        String ovfDescriptor = getRetriever().retrieveAsString(ovfUri);

        OvfCreateImportSpecParams params = new OvfCreateImportSpecParams();
        params.setHostSystem(host);
        params.setLocale("US");
        params.setEntityName(vmName);

        if (deploymentConfig == null) {
            deploymentConfig = "";
        }
        params.setDeploymentOption(deploymentConfig);

        params.getNetworkMapping().addAll(networks);
        params.setDiskProvisioning(OvfCreateImportSpecParamsDiskProvisioningType.THIN.name());

        if (ovfProps != null) {
            params.getPropertyMapping().addAll(ovfProps);
        }

        ManagedObjectReference ovfManager = this.connection.getServiceContent().getOvfManager();

        OvfCreateImportSpecResult importSpecResult = getVimPort().createImportSpec(ovfManager, ovfDescriptor,
                resourcePool, datastore, params);

        if (!importSpecResult.getError().isEmpty()) {
            return VimUtils.rethrow(importSpecResult.getError().get(0));
        }

        long totalBytes = getImportSizeBytes(importSpecResult);

        ManagedObjectReference lease = getVimPort().importVApp(resourcePool, importSpecResult.getImportSpec(),
                vmFolder, host);

        LeaseProgressUpdater leaseUpdater = new LeaseProgressUpdater(this.connection, lease, totalBytes);

        GetMoRef get = new GetMoRef(this.connection);
        HttpNfcLeaseInfo httpNfcLeaseInfo;

        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
        try {
            leaseUpdater.awaitReady();
            logger.info("Lease ready");

            // start updating the lease
            leaseUpdater.start(executorService);

            httpNfcLeaseInfo = get.entityProp(lease, PROP_INFO);

            List<HttpNfcLeaseDeviceUrl> deviceUrls = httpNfcLeaseInfo.getDeviceUrl();

            String ip = this.connection.getURI().getHost();

            String basePath = extractParentPath(ovfUri);

            for (HttpNfcLeaseDeviceUrl deviceUrl : deviceUrls) {
                String deviceKey = deviceUrl.getImportKey();

                for (OvfFileItem ovfFileItem : importSpecResult.getFileItem()) {
                    if (deviceKey.equals(ovfFileItem.getDeviceId())) {
                        logger.debug("Importing device id: {}", deviceKey);
                        String sourceUri = basePath + ovfFileItem.getPath();
                        String uploadUri = makUploadUri(ip, deviceUrl);
                        uploadVmdkFile(ovfFileItem, sourceUri, uploadUri, leaseUpdater,
                                this.ovfRetriever.getClient());
                        logger.info("Completed uploading VMDK file {}", sourceUri);
                    }
                }
            }

            // complete lease
            leaseUpdater.complete();
        } catch (Exception e) {
            leaseUpdater.abort(VimUtils.convertExceptionToFault(e));
            logger.info("Error importing ovf", e);
            throw e;
        } finally {
            executorService.shutdown();
        }

        httpNfcLeaseInfo = get.entityProp(lease, PROP_INFO);
        ManagedObjectReference entity = httpNfcLeaseInfo.getEntity();

        // as this is an OVF it makes sense to enable the OVF transport
        // only the guestInfo is enabled by default
        VmConfigSpec spec = new VmConfigSpec();
        spec.getOvfEnvironmentTransport().add(TRANSPORT_GUESTINFO);
        VirtualMachineConfigSpec reconfig = new VirtualMachineConfigSpec();
        reconfig.setVAppConfig(spec);

        ManagedObjectReference reconfigTask = getVimPort().reconfigVMTask(entity, reconfig);
        VimUtils.waitTaskEnd(this.connection, reconfigTask);

        return entity;
    }

    private String makUploadUri(String ip, HttpNfcLeaseDeviceUrl deviceUrl) {
        return deviceUrl.getUrl().replace("*", ip);
    }

    private String extractParentPath(URI ovfUri) {
        return ovfUri.toString().substring(0, ovfUri.toString().lastIndexOf("/") + 1);
    }

    private void uploadVmdkFile(OvfFileItem ovfFileItem, String sourceUri, String uploadUri,
            LeaseProgressUpdater leaseUpdater, HttpClient client) throws IOException {

        //prepare upload method
        HttpEntityEnclosingRequestBase upload;
        if (ovfFileItem.isCreate()) {
            upload = new HttpPut(uploadUri);
        } else {
            upload = new HttpPost(uploadUri);
        }

        upload.setHeader(Operation.CONTENT_TYPE_HEADER, CONTENT_TYPE_VMDK);

        HttpEntity entityToUpload;

        if (sourceUri.startsWith("file:/")) {
            entityToUpload = new FileEntity(new File(URI.create(sourceUri)));
        } else {
            //prepare download method
            HttpGet download = new HttpGet(sourceUri);

            //start download
            HttpResponse downloadResponse = client.execute(download);
            entityToUpload = downloadResponse.getEntity();
        }

        //chain download to upload
        upload.setEntity(newCountingEntity(entityToUpload, leaseUpdater));

        //start chained upload
        HttpResponse uploadResponse = client.execute(upload);

        //block until upload completes
        EntityUtils.consume(uploadResponse.getEntity());
    }

    private CountingEntityWrapper newCountingEntity(HttpEntity httpEntity, LeaseProgressUpdater leaseUpdater) {
        return new CountingEntityWrapper(httpEntity, leaseUpdater);
    }

    public OvfRetriever getRetriever() {
        return this.ovfRetriever;
    }
}