Hello Greg Padgett,

I'd like you to do a code review.  Please visit

    http://gerrit.ovirt.org/22139

to review the following change.

Change subject: restapi: cloud-init - rest api for start vm
......................................................................

restapi: cloud-init - rest api for start vm

Support using cloud-init to perform initial setup of virtual machines.

Further details available at:
http://www.ovirt.org/Features/Cloud-Init_Integration

This patch adds support for specifying Cloud-Init configuration when
starting a VM using the REST API.

Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1039009
Change-Id: I6ad0bfeca23cf8d4b2887010081d63c258032611
Signed-off-by: Greg Padgett <gpadg...@redhat.com>
Signed-off-by: Omer Frenkel <ofren...@redhat.com>
---
A 
backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/model/PayloadEncoding.java
M 
backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
M 
backend/manager/modules/restapi/interface/definition/src/main/resources/rsdl_metadata.yaml
M 
backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendCapabilitiesResource.java
M 
backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendVmResource.java
M 
backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/utils/FeaturesHelper.java
A 
backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/CloudInitValidator.java
M 
backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/VmValidator.java
M 
backend/manager/modules/restapi/types/src/main/java/org/ovirt/engine/api/restapi/types/VmMapper.java
9 files changed, 354 insertions(+), 10 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/39/22139/1

diff --git 
a/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/model/PayloadEncoding.java
 
b/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/model/PayloadEncoding.java
new file mode 100644
index 0000000..a6c1243
--- /dev/null
+++ 
b/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/model/PayloadEncoding.java
@@ -0,0 +1,18 @@
+package org.ovirt.engine.api.model;
+
+public enum PayloadEncoding {
+    BASE64,
+    PLAINTEXT;
+
+    public String value() {
+        return name().toLowerCase();
+    }
+
+    public static PayloadEncoding fromValue(String value) {
+        try {
+            return valueOf(value.toUpperCase());
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+}
diff --git 
a/backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
 
b/backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
index ec4237a..47424ae 100644
--- 
a/backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
+++ 
b/backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
@@ -605,6 +605,7 @@
           <xs:element ref="authentication_methods" minOccurs="0"/>
           <!--  Extrenal tasks -->
           <xs:element ref="step_types" minOccurs="0"/>
+          <xs:element ref="payload_encodings" minOccurs="0"/>
           <!-- Gluster related -->
           <xs:element ref="gluster_volume_types" minOccurs="0"/>
           <xs:element ref="transport_types" minOccurs="0"/>
@@ -951,6 +952,20 @@
         <xs:annotation>
           <xs:appinfo>
             <jaxb:property name="ScsiGenericIoOptions"/>
+          </xs:appinfo>
+        </xs:annotation>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="payload_encodings" type="PayloadEncodings"/>
+
+  <xs:complexType name="PayloadEncodings">
+    <xs:sequence>
+      <xs:element name="payload_encodings" type="xs:string" minOccurs="0" 
maxOccurs="unbounded">
+        <xs:annotation>
+          <xs:appinfo>
+            <jaxb:property name="PayloadEncodings"/>
           </xs:appinfo>
         </xs:annotation>
       </xs:element>
@@ -2368,8 +2383,74 @@
   <xs:complexType name="Initialization">
       <xs:sequence>
         <xs:element name="configuration" type="Configuration" minOccurs="0" 
maxOccurs="1"/>
+        <xs:element name="cloud_init" type="CloudInit" minOccurs="0" 
maxOccurs="1"/>
       </xs:sequence>
-   </xs:complexType>
+  </xs:complexType>
+
+  <xs:element name="dns" type="DNS"/>
+
+  <xs:complexType name="DNS">
+    <xs:sequence>
+      <xs:element name="servers" type="Hosts" minOccurs="0" maxOccurs="1"/>
+      <xs:element name="search_domains" type="Hosts" minOccurs="0" 
maxOccurs="1"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="authorized_key" type="AuthorizedKey"/>
+
+  <xs:element name="authorized_keys" type="AuthorizedKeys"/>
+
+  <xs:complexType name="AuthorizedKey">
+    <xs:annotation>
+      <xs:appinfo>
+        <jaxb:class name="AuthorizedKey"/>
+      </xs:appinfo>
+    </xs:annotation>
+    <xs:complexContent>
+      <xs:extension base="BaseResource">
+        <xs:sequence>
+          <xs:element ref="user" minOccurs="0" maxOccurs="1"/>
+          <xs:element name="key" type="xs:string" minOccurs="0" maxOccurs="1"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
+  <xs:complexType name="AuthorizedKeys">
+    <xs:complexContent>
+      <xs:extension base="BaseResources">
+        <xs:sequence>
+          <xs:annotation>
+            <xs:appinfo>
+              <jaxb:property name="AuthorizedKeys"/>
+            </xs:appinfo>
+          </xs:annotation>
+          <xs:element ref="authorized_key" minOccurs="0" 
maxOccurs="unbounded"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
+  <xs:element name="cloud_init" type="CloudInit"/>
+
+  <xs:complexType name="CloudInit">
+    <xs:sequence>
+      <xs:element ref="host" minOccurs="0"/>
+      <xs:element name="network" minOccurs="0">
+        <xs:complexType>
+          <xs:sequence>
+            <xs:element ref="nics" minOccurs="0"/>
+            <xs:element ref="dns" minOccurs="0"/>
+          </xs:sequence>
+        </xs:complexType>
+      </xs:element> <!-- </network> -->
+      <xs:element ref="authorized_keys" minOccurs="0"/>
+      <xs:element name="regenerate_ssh_keys" type="xs:boolean" minOccurs="0"/>
+      <xs:element name="timezone" type="xs:string" minOccurs="0"/>
+      <xs:element ref="users" minOccurs="0"/>
+      <xs:element ref="files" minOccurs="0" maxOccurs="1"/>
+    </xs:sequence>
+  </xs:complexType>
 
   <xs:complexType name="VmPlacementPolicy">
     <xs:sequence>
@@ -2807,6 +2888,8 @@
           <xs:element ref="port_mirroring" minOccurs="0" maxOccurs="1"/> <!-- 
Deprecated, replaced by 'vnic_profile' -->
           <xs:element ref="reported_devices" minOccurs="0" maxOccurs="1"/>
           <xs:element ref="vnic_profile" minOccurs="0" maxOccurs="1"/>
+          <xs:element name="boot_protocol" type="xs:string" minOccurs="0"/>
+          <xs:element name="on_boot" type="xs:boolean" minOccurs="0"/>
         </xs:sequence>
       </xs:extension>
     </xs:complexContent>
diff --git 
a/backend/manager/modules/restapi/interface/definition/src/main/resources/rsdl_metadata.yaml
 
b/backend/manager/modules/restapi/interface/definition/src/main/resources/rsdl_metadata.yaml
index 2f6520d..ab0caa0 100644
--- 
a/backend/manager/modules/restapi/interface/definition/src/main/resources/rsdl_metadata.yaml
+++ 
b/backend/manager/modules/restapi/interface/definition/src/main/resources/rsdl_metadata.yaml
@@ -282,7 +282,25 @@
           action.async: 'xs:boolean', action.vm.os.kernel: 'xs:string', 
action.grace_period.expiry: 'xs:long',
           action.vm.display.type: 'xs:string', action.vm.stateless: 
'xs:boolean', action.vm.os.cmdline: 'xs:string',
           action.vm.domain.user.username: 'xs:string', action.pause: 
'xs:boolean',
-          action.vm.os.boot--COLLECTION: {boot.dev: 'xs:string'}, 
action.vm.domain.user.password: 'xs:string'}
+          action.vm.os.boot--COLLECTION: {boot.dev: 'xs:string'}, 
action.vm.domain.user.password: 'xs:string',
+          action.vm.initialization.cloud-init: {cloud-init.hostname: 
'xs:string',
+          cloud-init.network.nics.nic--COLLECTION: {nic.name: 'xs:string',
+          nic.boot_protocol: 'xs:string',
+          nic.network.address.ip: 'xs:string',
+          nic.network.address.netmask: 'xs:string',
+          nic.network.address.gateway: 'xs:string',
+          nic.onboot: 'xs:boolean'},
+          cloud-init.network.dns.servers.host--COLLECTION: {host.address: 
'xs:string'},
+          cloud-init.network.dns.search_domains.host--COLLECTION: 
{host.address: 'xs:string'},
+          cloud-init.authorized_keys.authorized_key--COLLECTION: 
{authorized_key.key: 'xs:string',
+          authorized_key.user.name: 'xs:string'},
+          cloud-init.regenerate_ssh_keys: 'xs:boolean',
+          cloud-init.timezone: 'xs:string',
+          cloud-init.users.user--COLLECTION: {user.password: 'xs:string',
+          user.name: 'xs:string'},
+          cloud-init.payload_files.payload_file--COLLECTION: 
{payload_file.name: 'xs:string',
+          payload_file.content: 'xs:string',
+          payload_file.type: 'xs:string'}}}
         description: start a virtual machine in the system identified by the 
given id with the options specified in the request body
     urlparams: {}
     headers:
diff --git 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendCapabilitiesResource.java
 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendCapabilitiesResource.java
index 4c228d1..889d1af 100644
--- 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendCapabilitiesResource.java
+++ 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendCapabilitiesResource.java
@@ -57,6 +57,8 @@
 import org.ovirt.engine.api.model.OsType;
 import org.ovirt.engine.api.model.OsTypeUtils;
 import org.ovirt.engine.api.model.OsTypes;
+import org.ovirt.engine.api.model.PayloadEncoding;
+import org.ovirt.engine.api.model.PayloadEncodings;
 import org.ovirt.engine.api.model.Permit;
 import org.ovirt.engine.api.model.PermitType;
 import org.ovirt.engine.api.model.Permits;
@@ -236,6 +238,7 @@
         addWatchdogModels(version, WatchdogModel.values());
         addConfigurationTypes(version, ConfigurationType.values());
         addSnapshotStatuses(version, SnapshotStatus.values());
+        addPayloadEncodings(version, PayloadEncoding.values());
 
         // External tasks types
         addStepEnumTypes(version, StepEnum.values());
@@ -263,6 +266,15 @@
         }
     }
 
+    private void addPayloadEncodings(VersionCaps version, PayloadEncoding[] 
values) {
+        if (VersionUtils.greaterOrEqual(version, VERSION_3_3)) {
+            version.setPayloadEncodings(new PayloadEncodings());
+            for (PayloadEncoding mode : values) {
+                
version.getPayloadEncodings().getPayloadEncodings().add(mode.value());
+            }
+        }
+    }
+
     private void addCpuModes(VersionCaps version, CpuMode[] values) {
         if (VersionUtils.greaterOrEqual(version, VERSION_3_2)) {
             version.setCpuModes(new CpuModes());
diff --git 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendVmResource.java
 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendVmResource.java
index 3dccc3f..c0219ef 100644
--- 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendVmResource.java
+++ 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/BackendVmResource.java
@@ -1,17 +1,25 @@
 package org.ovirt.engine.api.restapi.resource;
 
+import static 
org.ovirt.engine.api.restapi.resource.BackendVmsResource.SUB_COLLECTIONS;
+import static org.ovirt.engine.core.utils.Ticketing.GenerateOTP;
+
 import java.util.List;
 import java.util.Set;
+
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
+
 import org.ovirt.engine.api.common.util.DetailHelper;
 import org.ovirt.engine.api.common.util.DetailHelper.Detail;
 import org.ovirt.engine.api.common.util.LinkHelper;
 import org.ovirt.engine.api.model.Action;
+import org.ovirt.engine.api.model.AuthorizedKey;
 import org.ovirt.engine.api.model.CdRom;
 import org.ovirt.engine.api.model.CdRoms;
 import org.ovirt.engine.api.model.Certificate;
+import org.ovirt.engine.api.model.CloudInit;
 import org.ovirt.engine.api.model.CreationStatus;
 import org.ovirt.engine.api.model.Display;
 import org.ovirt.engine.api.model.Statistic;
@@ -34,6 +42,7 @@
 import org.ovirt.engine.api.restapi.types.VmMapper;
 import org.ovirt.engine.core.common.VdcObjectType;
 import org.ovirt.engine.core.common.action.ChangeVMClusterParameters;
+import org.ovirt.engine.core.common.action.CloudInitParameters;
 import org.ovirt.engine.core.common.action.MigrateVmParameters;
 import org.ovirt.engine.core.common.action.MigrateVmToServerParameters;
 import org.ovirt.engine.core.common.action.MoveVmParameters;
@@ -48,6 +57,7 @@
 import org.ovirt.engine.core.common.action.VdcActionType;
 import org.ovirt.engine.core.common.action.VmManagementParametersBase;
 import org.ovirt.engine.core.common.action.VmOperationParameterBase;
+import org.ovirt.engine.core.common.businessentities.InitializationType;
 import org.ovirt.engine.core.common.businessentities.VDS;
 import org.ovirt.engine.core.common.businessentities.VDSGroup;
 import org.ovirt.engine.core.common.businessentities.VmStatic;
@@ -57,10 +67,6 @@
 import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
 import org.ovirt.engine.core.common.queries.VdcQueryType;
 import org.ovirt.engine.core.compat.Guid;
-
-
-import static 
org.ovirt.engine.api.restapi.resource.BackendVmsResource.SUB_COLLECTIONS;
-import static org.ovirt.engine.core.utils.Ticketing.GenerateOTP;
 
 public class BackendVmResource extends
         AbstractBackendActionableResource<VM, 
org.ovirt.engine.core.common.businessentities.VM> implements
@@ -234,6 +240,23 @@
                 validateParameters(vm.getPlacementPolicy(), "host.id|name");
                 
params.setDestinationVdsId(getHostId(vm.getPlacementPolicy().getHost()));
             }
+            if (vm.isSetInitialization() && 
vm.getInitialization().isSetCloudInit()) {
+                CloudInit cloudInit = vm.getInitialization().getCloudInit();
+                // currently only 'root' user is supported, alert the user if 
other user sent
+                if (cloudInit.isSetAuthorizedKeys()) {
+                    for (AuthorizedKey authKey : 
cloudInit.getAuthorizedKeys().getAuthorizedKeys()) {
+                        if (!"root".equals(authKey.getUser().getUserName())) {
+                            throw new 
WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
+.entity("Currently only the user 'root' is supported for authorized keys")
+.build());
+                        }
+                    }
+                }
+                params.setInitializationType(InitializationType.CloudInit);
+                ((RunVmOnceParams) params).setCloudInitParameters(
+                        getMapper(CloudInit.class, CloudInitParameters.class)
+                                .map(cloudInit, null));
+            }
         } else {
             actionType = VdcActionType.RunVm;
             params = new RunVmParams(guid);
diff --git 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/utils/FeaturesHelper.java
 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/utils/FeaturesHelper.java
index 58f0bf2..c0dafe0 100644
--- 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/utils/FeaturesHelper.java
+++ 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/utils/FeaturesHelper.java
@@ -70,6 +70,7 @@
             addGlusterHooksFeature(features);
             addFeatureReportVmFQDN(features);
             addFeatureAttachDiskSnapshot(features);
+            addFeatureCloudInit(features);
         }
         return features;
     }
@@ -374,4 +375,12 @@
         feature.setDescription("Ability to report the fully qualified domain 
name (FQDN) of a Virtual Machine");
         features.getFeature().add(feature);
     }
+
+    private void addFeatureCloudInit(Features features) {
+        Feature feature = new Feature();
+        feature.setName("Cloud Init");
+        feature.setDescription("Support for VM initialization with Cloud 
Init.");
+        features.getFeature().add(feature);
+    }
+
 }
diff --git 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/CloudInitValidator.java
 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/CloudInitValidator.java
new file mode 100644
index 0000000..626225c
--- /dev/null
+++ 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/CloudInitValidator.java
@@ -0,0 +1,34 @@
+package org.ovirt.engine.api.restapi.resource.validation;
+
+import static org.ovirt.engine.api.common.util.EnumValidator.validateEnum;
+
+import org.ovirt.engine.api.model.BootProtocol;
+import org.ovirt.engine.api.model.CloudInit;
+import org.ovirt.engine.api.model.File;
+import org.ovirt.engine.api.model.NIC;
+import org.ovirt.engine.api.model.PayloadEncoding;
+
+@ValidatedClass(clazz = CloudInit.class)
+public class CloudInitValidator implements Validator<CloudInit> {
+
+    @Override
+    public void validateEnums(CloudInit model) {
+        if (model != null) {
+            if (model.isSetNetwork()) {
+                if (model.getNetwork().isSetNics()
+                        && !model.getNetwork().getNics().getNics().isEmpty()) {
+                    for (NIC iface : model.getNetwork().getNics().getNics()) {
+                        validateEnum(BootProtocol.class, 
iface.getBootProtocol(), true);
+                    }
+                }
+            }
+            if (model.isSetFiles()
+                    && model.getFiles().isSetFiles()
+                    && !model.getFiles().getFiles().isEmpty()) {
+                for (File file : model.getFiles().getFiles()) {
+                    validateEnum(PayloadEncoding.class, file.getType(), true);
+                }
+            }
+        }
+    }
+}
diff --git 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/VmValidator.java
 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/VmValidator.java
index 69e53a4..06fa1ad 100644
--- 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/VmValidator.java
+++ 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/VmValidator.java
@@ -1,10 +1,10 @@
 package org.ovirt.engine.api.restapi.resource.validation;
 
+import static org.ovirt.engine.api.common.util.EnumValidator.validateEnum;
+
 import org.ovirt.engine.api.model.Payload;
 import org.ovirt.engine.api.model.VM;
 import org.ovirt.engine.api.model.VmType;
-
-import static org.ovirt.engine.api.common.util.EnumValidator.validateEnum;
 
 @ValidatedClass(clazz = VM.class)
 public class VmValidator implements Validator<VM> {
@@ -15,6 +15,7 @@
     private PlacementPolicyValidator placementPolicyValidator = new 
PlacementPolicyValidator();
     private PayloadValidator payloadValidator = new PayloadValidator();
     private ConfigurationValidator configurationValidator = new 
ConfigurationValidator();
+    private CloudInitValidator cloudInitValidator = new CloudInitValidator();
 
     @Override
     public void validateEnums(VM vm) {
@@ -38,9 +39,13 @@
                 payloadValidator.validateEnums(payload);
             }
         }
-
         if (vm.isSetInitialization() && 
vm.getInitialization().isSetConfiguration()) {
             
configurationValidator.validateEnums(vm.getInitialization().getConfiguration());
         }
+        if (vm.isSetInitialization()) {
+            if (vm.getInitialization().isSetCloudInit()) {
+                
cloudInitValidator.validateEnums(vm.getInitialization().getCloudInit());
+            }
+        }
     }
 }
diff --git 
a/backend/manager/modules/restapi/types/src/main/java/org/ovirt/engine/api/restapi/types/VmMapper.java
 
b/backend/manager/modules/restapi/types/src/main/java/org/ovirt/engine/api/restapi/types/VmMapper.java
index 56450d4..e0e1795 100644
--- 
a/backend/manager/modules/restapi/types/src/main/java/org/ovirt/engine/api/restapi/types/VmMapper.java
+++ 
b/backend/manager/modules/restapi/types/src/main/java/org/ovirt/engine/api/restapi/types/VmMapper.java
@@ -3,6 +3,7 @@
 import static org.ovirt.engine.core.compat.Guid.createGuidFromString;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -10,9 +11,12 @@
 
 import org.apache.commons.lang.StringUtils;
 import org.ovirt.engine.api.common.util.StatusUtils;
+import org.ovirt.engine.api.model.AuthorizedKey;
 import org.ovirt.engine.api.model.Boot;
 import org.ovirt.engine.api.model.BootDevice;
+import org.ovirt.engine.api.model.BootProtocol;
 import org.ovirt.engine.api.model.CPU;
+import org.ovirt.engine.api.model.CloudInit;
 import org.ovirt.engine.api.model.Cluster;
 import org.ovirt.engine.api.model.ConfigurationType;
 import org.ovirt.engine.api.model.CpuMode;
@@ -24,20 +28,23 @@
 import org.ovirt.engine.api.model.DisplayType;
 import org.ovirt.engine.api.model.Domain;
 import org.ovirt.engine.api.model.File;
+import org.ovirt.engine.api.model.Files;
 import org.ovirt.engine.api.model.GuestInfo;
 import org.ovirt.engine.api.model.HighAvailability;
 import org.ovirt.engine.api.model.Host;
 import org.ovirt.engine.api.model.IP;
 import org.ovirt.engine.api.model.IPs;
 import org.ovirt.engine.api.model.MemoryPolicy;
+import org.ovirt.engine.api.model.NIC;
 import org.ovirt.engine.api.model.OperatingSystem;
 import org.ovirt.engine.api.model.OsType;
 import org.ovirt.engine.api.model.Payload;
-import org.ovirt.engine.api.model.Files;
+import org.ovirt.engine.api.model.PayloadEncoding;
 import org.ovirt.engine.api.model.Quota;
 import org.ovirt.engine.api.model.Template;
 import org.ovirt.engine.api.model.Usb;
 import org.ovirt.engine.api.model.UsbType;
+import org.ovirt.engine.api.model.User;
 import org.ovirt.engine.api.model.VCpuPin;
 import org.ovirt.engine.api.model.VM;
 import org.ovirt.engine.api.model.VmAffinity;
@@ -48,6 +55,8 @@
 import org.ovirt.engine.api.restapi.utils.CustomPropertiesParser;
 import org.ovirt.engine.api.restapi.utils.GuidUtils;
 import org.ovirt.engine.api.restapi.utils.UsbMapperUtils;
+import org.ovirt.engine.core.common.action.CloudInitParameters;
+import org.ovirt.engine.core.common.action.CloudInitParameters.Attachment;
 import org.ovirt.engine.core.common.action.RunVmOnceParams;
 import org.ovirt.engine.core.common.businessentities.BootSequence;
 import org.ovirt.engine.core.common.businessentities.MigrationSupport;
@@ -58,6 +67,8 @@
 import org.ovirt.engine.core.common.businessentities.VmPayload;
 import org.ovirt.engine.core.common.businessentities.VmStatic;
 import org.ovirt.engine.core.common.businessentities.VmTemplate;
+import 
org.ovirt.engine.core.common.businessentities.network.NetworkBootProtocol;
+import 
org.ovirt.engine.core.common.businessentities.network.VdsNetworkInterface;
 import org.ovirt.engine.core.common.osinfo.OsRepository;
 import org.ovirt.engine.core.common.utils.SimpleDependecyInjector;
 import org.ovirt.engine.core.common.utils.VmDeviceType;
@@ -902,6 +913,137 @@
         return entity;
     }
 
+    @Mapping(from = Attachment.AttachmentType.class, to = 
PayloadEncoding.class)
+    public static PayloadEncoding map(Attachment.AttachmentType 
attachmentType, PayloadEncoding template) {
+        switch (attachmentType) {
+            case BASE64:            return PayloadEncoding.BASE64;
+            case PLAINTEXT:         return PayloadEncoding.PLAINTEXT;
+            default:                return null;
+        }
+    }
+
+    @Mapping(from = PayloadEncoding.class, to = 
Attachment.AttachmentType.class)
+    public static Attachment.AttachmentType map(PayloadEncoding 
attachmentType, Attachment.AttachmentType template) {
+        switch (attachmentType) {
+            case BASE64:            return Attachment.AttachmentType.BASE64;
+            case PLAINTEXT:         return Attachment.AttachmentType.PLAINTEXT;
+            default:                return null;
+        }
+    }
+
+    @Mapping(from = CloudInit.class, to = CloudInitParameters.class)
+    public static CloudInitParameters map(CloudInit model, CloudInitParameters 
template) {
+        CloudInitParameters entity = template != null ? template : new 
CloudInitParameters();
+
+        if (model.isSetHost() && model.getHost().isSetAddress()) {
+            entity.setHostname(model.getHost().getAddress());
+        }
+
+        if (model.isSetAuthorizedKeys()
+                && model.getAuthorizedKeys().isSetAuthorizedKeys()
+                && !model.getAuthorizedKeys().getAuthorizedKeys().isEmpty()) {
+            StringBuilder keys = new StringBuilder();
+            for (AuthorizedKey authKey : 
model.getAuthorizedKeys().getAuthorizedKeys()) {
+                if (keys.length() > 0) {
+                    keys.append("\n");
+                }
+                keys.append(authKey.getKey());
+            }
+            entity.setAuthorizedKeys(keys.toString());
+        }
+
+        if (model.isSetRegenerateSshKeys()) {
+            entity.setRegenerateKeys(model.isRegenerateSshKeys());
+        }
+
+        if (model.isSetNetwork()) {
+            if (model.getNetwork().isSetNics()) {
+                Map<String, VdsNetworkInterface> interfaces = new HashMap<>();
+                for (NIC iface : model.getNetwork().getNics().getNics()) {
+                    VdsNetworkInterface vdsNetworkInterface = new 
VdsNetworkInterface();
+                    if (iface.isSetBootProtocol()) {
+                        NetworkBootProtocol protocol = 
HostNicMapper.map(BootProtocol.fromValue(iface.getBootProtocol()), null);
+                        vdsNetworkInterface.setBootProtocol(protocol);
+                        if (protocol != NetworkBootProtocol.DHCP && 
iface.isSetNetwork() && iface.getNetwork().isSetIp()) {
+                            if (iface.getNetwork().getIp().isSetAddress()) {
+                                
vdsNetworkInterface.setAddress(iface.getNetwork().getIp().getAddress());
+                            }
+                            if (iface.getNetwork().getIp().isSetNetmask()) {
+                                
vdsNetworkInterface.setSubnet(iface.getNetwork().getIp().getNetmask());
+                            }
+                            if (iface.getNetwork().getIp().isSetGateway()) {
+                                
vdsNetworkInterface.setGateway(iface.getNetwork().getIp().getGateway());
+                            }
+                        }
+                    }
+
+                    interfaces.put(iface.getName(), vdsNetworkInterface);
+
+                    if (iface.isSetOnBoot() && iface.isOnBoot()) {
+                        if (entity.getStartOnBoot() == null) {
+                            entity.setStartOnBoot(new ArrayList<String>());
+                        }
+                        entity.getStartOnBoot().add(iface.getName());
+                    }
+                }
+
+                entity.setInterfaces(interfaces);
+            }
+            if (model.getNetwork().isSetDns()) {
+                if (model.getNetwork().getDns().isSetServers()
+                        && 
model.getNetwork().getDns().getServers().isSetHosts()
+                        && 
!model.getNetwork().getDns().getServers().getHosts().isEmpty()) {
+                    List<String> dnsServers = new ArrayList<>();
+                    for (Host host : 
model.getNetwork().getDns().getServers().getHosts()) {
+                        if (host.isSetAddress()) {
+                            dnsServers.add(host.getAddress());
+                        }
+                    }
+                    entity.setDnsServers(dnsServers);
+                }
+
+                if (model.getNetwork().getDns().isSetSearchDomains()
+                        && 
model.getNetwork().getDns().getSearchDomains().isSetHosts()
+                        && 
!model.getNetwork().getDns().getSearchDomains().getHosts().isEmpty()) {
+                    List<String> searchDomains = new ArrayList<>();
+                    for (Host host : 
model.getNetwork().getDns().getSearchDomains().getHosts()) {
+                        if (host.isSetAddress()) {
+                            searchDomains.add(host.getAddress());
+                        }
+                    }
+                    entity.setDnsSearch(searchDomains);
+                }
+            }
+        }
+
+        if (model.isSetTimezone() && model.getTimezone() != null) {
+            entity.setTimeZone(model.getTimezone());
+        }
+
+        if (model.isSetUsers()) {
+            for (User user : model.getUsers().getUsers()) {
+                // currently only root password supported in backend
+                if ("root".equals(user.getUserName())) {
+                    entity.setRootPassword(user.getPassword());
+                }
+            }
+        }
+
+        if (model.isSetFiles()
+                && model.getFiles().isSetFiles()
+                && !model.getFiles().getFiles().isEmpty()) {
+            entity.setAttachments(new HashMap<String, Attachment>());
+            for (File file : model.getFiles().getFiles()) {
+                Attachment attachment = new Attachment();
+                
attachment.setAttachmentType(map(PayloadEncoding.fromValue(file.getType()), 
null));
+                attachment.setContent(file.getContent());
+                entity.getAttachments().put(file.getName(), attachment);
+            }
+        }
+
+        return entity;
+    }
+
     static String cpuTuneToString(final CpuTune tune) {
         final StringBuilder builder = new StringBuilder();
         boolean first = true;


-- 
To view, visit http://gerrit.ovirt.org/22139
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I6ad0bfeca23cf8d4b2887010081d63c258032611
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.3.2
Gerrit-Owner: Omer Frenkel <ofren...@redhat.com>
Gerrit-Reviewer: Greg Padgett <gpadg...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to