Bug 1305904 - Cloud-Init payload not passed into VM via python SDK
Summary: Cloud-Init payload not passed into VM via python SDK
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: ovirt-engine
Classification: oVirt
Component: RestAPI
Version: 3.6.2.6
Hardware: Unspecified
OS: Unspecified
medium
high
Target Milestone: ovirt-3.6.5
: 3.6.5
Assignee: Marek Libra
QA Contact: Israel Pinto
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2016-02-09 14:42 UTC by Vladimir Astafiev
Modified: 2019-10-10 11:10 UTC (History)
10 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2016-04-21 14:42:13 UTC
oVirt Team: Virt
Embargoed:
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 12:19 UTC, Israel Pinto
no flags Details


Links
System ID Private Priority Status Summary Last Updated
oVirt gerrit 54258 0 master MERGED restapi: Fixed missing cloud_init mapping 2016-03-02 14:05:55 UTC
oVirt gerrit 54265 0 ovirt-engine-3.6 MERGED restapi: Fixed missing cloud_init mapping 2016-03-02 15:53:23 UTC

Description Vladimir Astafiev 2016-02-09 14:42:37 UTC
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 15:02:01 UTC
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 15:02:06 UTC
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 15:19:03 UTC
(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 15:22:00 UTC
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 16:10:45 UTC
@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 16:15:14 UTC
What version of the engine exactly? Has that VM been started before sending that request?

Comment 7 Karim Boumedhel 2016-03-28 16:32:16 UTC
(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 19:01:48 UTC
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 19:06:55 UTC
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 12:56:02 UTC
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 11:02:04 UTC
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 12:18:25 UTC
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 12:19:28 UTC
Created attachment 1142962 [details]
sdk_test


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