Bug 1305904 - Cloud-Init payload not passed into VM via python SDK
Cloud-Init payload not passed into VM via python SDK
Status: CLOSED CURRENTRELEASE
Product: ovirt-engine
Classification: oVirt
Component: RestAPI (Show other bugs)
3.6.2.6
Unspecified Unspecified
medium Severity high (vote)
: ovirt-3.6.5
: 3.6.5
Assigned To: Marek Libra
Israel Pinto
: Regression
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2016-02-09 09:42 EST by Vladimir Astafiev
Modified: 2016-10-05 09:47 EDT (History)
10 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2016-04-21 10:42:13 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: Virt
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---
rule-engine: ovirt‑3.6.z+
rule-engine: blocker+
mgoldboi: planning_ack+
tjelinek: devel_ack+
mavital: testing_ack+


Attachments (Terms of Use)
sdk_test (2.55 KB, text/plain)
2016-04-03 08:19 EDT, Israel Pinto
no flags Details


External Trackers
Tracker ID Priority Status Summary Last Updated
oVirt gerrit 54258 master MERGED restapi: Fixed missing cloud_init mapping 2016-03-02 09:05 EST
oVirt gerrit 54265 ovirt-engine-3.6 MERGED restapi: Fixed missing cloud_init mapping 2016-03-02 10:53 EST

  None (edit)
Description Vladimir Astafiev 2016-02-09 09:42:37 EST
Description of problem:

Before the update to 3.6.2 I used this code to initialize VMs via Cloud-Init with python SDK:

cloud_init = params.CloudInit(regenerate_ssh_keys=True, users=params.Users(user=[params.User(user_name="root", password=ROOTPASSWORD)]),
                              files=files, host=host, network_configuration=params.NetworkConfiguration(
                                                          nics=params.Nics(nic=[params.NIC(name='eth0',
                                                              boot_protocol='static',
                                                              on_boot=True,
                                                              network=params.Network(ip=params.IP(address=IPADDRESS, netmask=NETMASK, gateway=GATEWAY)))]),
                                                          dns=params.DNS(servers=params.Hosts(host=[params.Host(address=DNS1),params.Host(address=DNS2)]))))

action = params.Action(use_cloud_init=True, vm=params.VM(initialization=params.Initialization(regenerate_ssh_keys=True, cloud_init=cloud_init)))
vm.start(action=action)



Version-Release number of selected component (if applicable):
ovirt-engine-3.6.2.6-1.el7.centos.noarch
ovirt-engine-sdk-python-3.6.2.1-1.el7.centos.noarch


How reproducible:
100%


Actual results:
After updating to 3.6.2 the code stopped working.


Expected results:
Payload passed to VM


Additional info:

After initializing I get this payload:


# ll -R /mnt
/mnt:
total 2
drwxr-xr-x. 3 root root 2048 Feb  2 19:25 openstack

/mnt/openstack:
total 2
drwxr-xr-x. 2 root root 2048 Feb  2 19:25 latest

/mnt/openstack/latest:
total 1
-rw-r-----. 1 root root 200 Feb  2 19:25 meta_data.json
-rw-r-----. 1 root root 316 Feb  2 19:25 user_data

# cat /mnt/openstack/latest/user_data
#cloud-config
ssh_pwauth: true
disable_root: 0
ssh_deletekeys: 'True'
output:
  all: '>> /var/log/cloud-init-output.log'
chpasswd:
  expire: false
runcmd:
- 'sed -i ''/^datasource_list: /d'' /etc/cloud/cloud.cfg; echo ''datasource_list:
  ["NoCloud", "ConfigDrive"]'' >> /etc/cloud/cloud.cfg'

# cat /mnt/openstack/latest/meta_data.json
{
  "launch_index" : "0",
  "availability_zone" : "nova",
  "uuid" : "d6309b89-c793-4db5-83bc-9c38a18b1bfa",
  "meta" : {
    "essential" : "false",
    "role" : "server",
    "dsmode" : "local"
  }
}
Comment 1 Juan Hernández 2016-02-09 10:02:01 EST
As you pointed out in the mailing list this regression was introduced by the following patch:

  restapi: Enable initialization via run-once
  https://gerrit.ovirt.org/50240

Basically that patch made it impossible to use the "cloud_init" element when starting a VM. To workaround this you can use the equivalent elements that are part of the "initialization" element. For example:

action = params.Action(
  use_cloud_init=True,
  vm=params.VM(
    initialization=params.Initialization(
      regenerate_ssh_keys=True,
      host_name="yourhostname",
      user_name="root",
      root_password=ROOTPASSWORD,
      nic_configurations=params.GuestNicsConfiguration(
        nic_configuration=[
          params.GuestNicConfiguration(
            name="eth0",
            boot_protocol="static",
            on_boot=True,
            ip=params.IP(
              address=IPADDRESS,
              netmask=NETMASK,
              gateway=GATEWAY,
            ),
          ),
        ],
      ),
      dns_servers="%s, %s" % (DNS1, DNS2),
    ),
  ),
)

Note that there isn't an equivalent to the "files" element inside "initialization", what are you using it for?
Comment 2 Red Hat Bugzilla Rules Engine 2016-02-09 10:02:06 EST
This bug report has Keywords: Regression or TestBlocker.
Since no regressions or test blockers are allowed between releases, it is also being identified as a blocker for this release. Please resolve ASAP.
Comment 3 Vladimir Astafiev 2016-02-09 10:19:03 EST
(In reply to Juan Hernández from comment #1)

> Note that there isn't an equivalent to the "files" element inside
> "initialization", what are you using it for?

def encode(s):
   return re.sub("\s+", "", base64.encodestring(s))

custom_script = '''
write_files:
- encoding: b64
  content: %s
  owner: root:root
  path: /path/to/file
  permissions: '0755'
runcmd:
 - some code
''' % encode(file_content)

files = params.Files(file=[params.File(name="custom_script", type_="plaintext", content=custom_script)])
cloud_init = params.CloudInit(files = files)
Comment 4 Juan Hernández 2016-02-09 10:22:00 EST
OK, in that case the equivalent is the "custom_script" element:

initialization=params.Initialization(
  ...
  custom_script=custom_script,
)
Comment 5 Karim Boumedhel 2016-03-28 12:10:45 EDT
@jhernandez,
also not handled though i m passing the following XML, as per your recommendation
<action>
  <vm>
     <initialization>
       <host_name>biloute</host_name>
       <domain>karma.local</domain>
       <regenerate_ssh_keys>true</regenerate_ssh_keys>
       <dns_servers>8.8.8.8</dns_servers>
       <nic_configurations>
         <nic_configuration>
           <name>eth0</name>
           <boot_protocol>DHCP</boot_protocol>
           <on_boot>true</on_boot>
         </nic_configuration>
       </nic_configurations>
       <root_password>unix1234567</root_password>
       <user_name>root</user_name>
     </initialization>
  </vm>
  <use_cloud_init>true</use_cloud_init>
</action>

payload doesnt contain the corresponding information
Comment 6 Juan Hernández 2016-03-28 12:15:14 EDT
What version of the engine exactly? Has that VM been started before sending that request?
Comment 7 Karim Boumedhel 2016-03-28 12:32:16 EDT
(In reply to Juan Hernández from comment #6)
> What version of the engine exactly? Has that VM been started before sending
> that request?

vm was started several times indeed.
testing is done on ovirt-engine-3.6.1.3-1.el7.centos.noarch
Comment 8 Juan Hernández 2016-03-28 15:01:48 EDT
Karim, I can't reproduce your problem. How did you check that the payload doesn't contain the information? Did you check the content of the CDROM that is attached to the VM? In case you didn't please try the following:

1. SSH to the hypervisor where the VM is running.

2. Look for the process corresponding to that VM, and find the value of the "-drive file=..." option:

  # ps -ef | grep your_vm_name | grep payload

Should be something like "-drive file=/var/run/vdsm/payload/...img".

3. Copy that file somwhere, to /tmp, for example:

  # cp /var/run/vdsm/payload/...img /tmp/cloudinit.img

4. Mount and inspect it:

  # mount -o loop,ro /tmp/cloudinit.img /mnt
  # find /mnt
  # cat /mnt/openstack/content/0000
  # cat /mnt/openstack/latest/meta_data.json
  # cat /mnt/openstack/latest/user_data

5. Unmount it:

  # umount /mnt

Please share your findings.
Comment 9 Karim Boumedhel 2016-03-28 15:06:55 EDT
indeed i directly check the payload
user_data -> 
#cloud-config
ssh_pwauth: true
disable_root: 0
output:
  all: '>> /var/log/cloud-init-output.log'
chpasswd:
  expire: false
runcmd:
- 'sed -i ''/^datasource_list: /d'' /etc/cloud/cloud.cfg; echo ''datasource_list:
  ["NoCloud", "ConfigDrive"]'' >> /etc/cloud/cloud.cfg'


metadata_json
{
  "launch_index" : "0",
  "availability_zone" : "nova",
  "uuid" : "6eec53d8-6715-48b5-acdb-a50c71164955",
  "meta" : {
    "essential" : "false",
    "role" : "server",
    "dsmode" : "local"
  }
}

to be complete here s the python code i use

ipinfo = params.IP(address=ip, netmask=netmask, gateway=gateway)
nic    = params.GuestNicConfiguration(name='eth0', boot_protocol='STATIC', ip=ipinfo, on_boot=True)
nics   = params.GuestNicsConfiguration(nic_configuration=[nic])
initialization=params.Initialization(regenerate_ssh_keys=True, host_name=hostname, domain=domain, user_name='root',root_password=rootpw, nic_configurations=nics, dns_servers=dns,authorized_ssh_keys=key)

action = params.Action(use_cloud_init=use_cloud_init,vm=params.VM(initialization=initialization))
vm.start(action=action)
Comment 10 Juan Hernández 2016-03-29 08:56:02 EDT
Karim the behaviour that you see is the effect of bug 1287122. That was fixed in version 3.6.2 of the engine (and introduced this regression). So if you need to use the workaround in the description then you need at least version 3.6.2.
Comment 11 Karim Boumedhel 2016-03-30 07:02:04 EDT
not sure if relevant to this bug but though my code correctly configures networking, 
hostname, domain  and root password are ignored
the hostname and domain dont even show up in the payload.
did you check this part ?
Comment 12 Israel Pinto 2016-04-03 08:18:25 EDT
Verify with:
RHEVMV: 3.6.5-0.1.el6 
python-sdk: rhevm-sdk-python.noarch 0:3.6.5.0-1.el7ev
Host:
OS Version:RHEL - 7.2 - 9.el7
Kernel Version:3.10.0 - 327.el7.x86_64
KVM Version:2.3.0 - 31.el7_2.10
LIBVIRT Version:libvirt-1.2.17-13.el7_2.2
VDSM Version:vdsm-4.17.25-0.el7ev

Steps:
using python sdk:
1. Create new vm from template with rhel guest image
2. Configure with cloud init: root passwork, static network.
3. Start VM
4. Login to VM with updated password
5  Check on host payload that all the parameters exists.

Results:
1. Payload is fill with configure parameters
2. Network is not set because of BZ in network see: https://bugzilla.redhat.com/show_bug.cgi?id=1288819

host payload:
# cat meta_data.json 
{
  "network-interfaces" : "auto eth0\niface eth0 inet static\n  address 192.168.1.1\n  netmask 255.255.255.0\n  gateway 192.168.1.254\n  dns-nameservers 10.35.1.110.35.1.2\n",
  "availability_zone" : "nova",
  "launch_index" : "0",
  "meta" : {
    "role" : "server",
    "dsmode" : "local",
    "essential" : "false"
  },
  "network_config" : {
    "path" : "/etc/network/interfaces",
    "content_path" : "/content/0000"
  },
  "uuid" : "923da6d0-c322-4f33-81d6-f4d452906f01"
}
# cat user_data 
#cloud-config
output:
  all: '>> /var/log/cloud-init-output.log'
password: '1'
disable_root: 0
runcmd:
- 'sed -i ''/^datasource_list: /d'' /etc/cloud/cloud.cfg; echo ''datasource_list:
  ["NoCloud", "ConfigDrive"]'' >> /etc/cloud/cloud.cfg'
ssh_deletekeys: 'True'
ssh_pwauth: true
chpasswd:
  expire: false
user: root

atached python code for testing.
Comment 13 Israel Pinto 2016-04-03 08:19 EDT
Created attachment 1142962 [details]
sdk_test

Note You need to log in before you can comment on or make changes to this bug.