This is a continuation of the
previous post on Ironic on a NUC - setting things up. If you're following along at home, read that first.
Creating disk images for deployment
Now let's build some images for use with Ironic. First off, we'll need a deploy ramdisk image for the initial load, and we'll also need the image that we want to deploy to the hardware. We can build these using diskimage builder, part of the triple-o effort.
So let's do that in a virtual environment:
mrda@irony:~/src$ mkvirtualenv dib
(dib)mrda@irony:~/src$ pip install diskimage-builder six
And because we want to use some of the triple-o elements, we'll refer to these as we do the build. Once the images are built we'll put them in a place where tftpd-hpa can serve them.
(dib)mrda@irony:~/src$ export ELEMENTS_PATH=~/src/tripleo-image-elements/elements
(dib)mrda@irony:~/src$ mkdir images
(dib)mrda@irony:~/src$ cd images
(dib)mrda@irony:~/src/images$ disk-image-create ubuntu baremetal localboot dhcp-all-interfaces local-config -o my-image
(dib)mrda@irony:~/src/images$ ramdisk-image-create ubuntu deploy-ironic -o deploy-ramdisk
(dib)mrda@irony:~/src/images$ cp -rp * /tftpboot
Starting Ironic services
I like to do my development in virtualenvs, so we'll run our services there. Let's start with ironic-api.
(dib)mrda@irony:~/src/images$ deactivate
mrda@irony:~/src/images$ cd ~/src/ironic/
mrda@irony:~/src/ironic (master)$ tox -evenv --notest
mrda@irony:~/src/ironic (master)$ source .tox/venv/bin/activate
(venv)mrda@irony:~/src/ironic (master)$ ironic-api -v -d --config-file etc/ironic/ironic.conf.local
Now in a new terminal window for our VM, let's run ironic-conductor:
mrda@irony:~/src/images$ cd ~/src/ironic/
mrda@irony:~/src/ironic (master)$ source .tox/venv/bin/activate
(venv)mrda@krypton:~/src/ironic (master)$ python setup.py develop
(venv)mrda@krypton:~/src/ironic (master)$ ironic-conductor -v -d --config-file etc/ironic/ironic.conf.local
(If you get an error about unable to load the pywsman library, follow the workaround over here in a
previous blog post)
Running Ironic Client
Let's open a new window on the VM for running an ironic command-line client to exercise what we've built:
mrda@irony:~$ cd src/python-ironicclient/
mrda@irony:~/src/python-ironicclient (master)$ tox -evenv --notest
mrda@irony:~/src/python-ironicclient (master)$ source .tox/venv/bin/activate
Now we need to fudge authentication, and point at our running ironic-api:
(venv)mrda@irony:~/src/python-ironicclient (master)$ export OS_AUTH_TOKEN=fake-token
(venv)mrda@irony:~/src/python-ironicclient (master)$ export IRONIC_URL=http://localhost:6385/
Let's try it out and see what happens, eh?
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic driver-list
+---------------------+----------------+
| Supported driver(s) | Active host(s) |
+---------------------+----------------+
| pxe_amt | test-host |
+---------------------+----------------+
Looking good! Let's try registering the NUC as an Ironic node, specifying the deployment ramdisk:
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic node-create -d pxe_amt -i amt_password='<the-nuc-amin-password>' -i amt_username='admin' -i amt_address='10.0.0.251' -i deploy_ramdisk='file:///tftpboot/deploy-ramdisk.initramfs' -i deploy_kernel='file:///tftpboot/deploy-ramdisk.kernel' -n thenuc
+--------------+--------------------------------------------------------------------------+
| Property | Value |
+--------------+--------------------------------------------------------------------------+
| uuid | 924a5447-930e-4d27-837e-6dd5d5f10e16 |
| driver_info | {u'amt_username': u'admin', u'deploy_kernel': u'file:///tftpboot/deploy- |
| | ramdisk.kernel', u'amt_address': u'10.0.0.251', u'deploy_ramdisk': |
| | u'file:///tftpboot/deploy-ramdisk.initramfs', u'amt_password': |
| | u'******'} |
| extra | {} |
| driver | pxe_amt |
| chassis_uuid | |
| properties | {} |
| name | thenuc |
+--------------+--------------------------------------------------------------------------+
Again more success! Since we're not using Nova to manage or kick-off the deploy, we need to tell ironic where the instance we want deployed is, along with some of the instance information:
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic node-update thenuc add instance_info/image_source='file:///tftpboot/my-image.qcow2' instance_info/kernel='file:///tftpboot/my-image.vmlinuz' instance_info/ramdisk='file:///tftpboot/my-image.initrd' instance_info/root_gb=10
+------------------------+-------------------------------------------------------------------------+
| Property | Value |
+------------------------+-------------------------------------------------------------------------+
| target_power_state | None |
| extra | {} |
| last_error | None |
| updated_at | None |
| maintenance_reason | None |
| provision_state | available |
| clean_step | {} |
| uuid | 924a5447-930e-4d27-837e-6dd5d5f10e16 |
| console_enabled | False |
| target_provision_state | None |
| provision_updated_at | None |
| maintenance | False |
| inspection_started_at | None |
| inspection_finished_at | None |
| power_state | None |
| driver | pxe_amt |
| reservation | None |
| properties | {} |
| instance_uuid | None |
| name | thenuc |
| driver_info | {u'amt_username': u'admin', u'amt_password': u'******', u'amt_address': |
| | u'10.0.0.251', u'deploy_ramdisk': u'file:///tftpboot/deploy- |
| | ramdisk.initramfs', u'deploy_kernel': u'file:///tftpboot/deploy- |
| | ramdisk.kernel'} |
| created_at | 2015-09-10T00:55:27+00:00 |
| driver_internal_info | {} |
| chassis_uuid | |
| instance_info | {u'ramdisk': u'file:///tftpboot/my-image.initrd', u'kernel': |
| | u'file:///tftpboot/my-image.vmlinuz', u'root_gb': 10, u'image_source': |
| | u'file:///tftpboot/my-image.qcow2'} |
+------------------------+-------------------------------------------------------------------------+
Let's see what we've got:
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic node-list
+--------------------------------------+--------+---------------+-------------+--------------------+-------------+
| UUID | Name | Instance UUID | Power State | Provisioning State | Maintenance |
+--------------------------------------+--------+---------------+-------------+--------------------+-------------+
| f8af4d4e-e3da-4a04-9596-8e4fef15e4eb | thenuc | None | None | available | False |
+--------------------------------------+--------+---------------+-------------+--------------------+-------------+
We now need to create a network port in ironic, and associate it with the mac address of the NUC. But I'm lazy, so let's extract the node UUID first:
(venv)mrda@irony:~/src/python-ironicclient (master)$ NODEUUID=$(ironic node-list | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic port-create -n $NODEUUID -a <nuc-mac-address>
+-----------+--------------------------------------+
| Property | Value |
+-----------+--------------------------------------+
| node_uuid | 924a5447-930e-4d27-837e-6dd5d5f10e16 |
| extra | {} |
| uuid | c6dddc3d-b9b4-4fbc-99e3-18b8017c7b01 |
| address | <nuc-mac-address> |
+-----------+--------------------------------------+
So let's validate everything we've done, before we try this out in anger:
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic node-validate thenuc
+------------+--------+---------------+
| Interface | Result | Reason |
+------------+--------+---------------+
| boot | True | |
| console | None | not supported |
| deploy | True | |
| inspect | None | not supported |
| management | True | |
| power | True | |
| raid | None | not supported |
+------------+--------+---------------+
And one more thing to do before we really start things rolling - ensure the NUC is listening to us:
(venv)mrda@irony:~/src/python-ironicclient (master)$ telnet 10.0.0.251 16992
Trying 10.0.0.251...
Connected to 10.0.0.251.
Escape character is '^]'.
^]close
telnet> close
Connection closed.
You might have to try that a couple of times to wake up the AMT interface, but it's important that you do to ensure you don't get a failed deploy.
And then we take the node active, which will DHCP the deploy ramdisk, which will in turn write the user image to the disk - if everything goes well. This will also take quite a long time, so time to go make that cup of tea :-)
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic node-set-provision-state thenuc active
Your NUC should have just booted into your user image and should be ready for you to use!
Postscript #1:
Actually, that's not what really happened. It's what I would have
liked to happen.
But there were some issues. Firstly, ironic-conductor complained about not being able to find 'ironic-rootwrap'. And then once I symlinked that into place, it couldn't find the config for rootwrap, so I symlinked that into place. Then it complained that
iscsiadm didn't have the correct permissions in rootwrap to do it's thing...
So I gave up, and did the thing I didn't want to. Back on the VM I ended up doing a "
sudo python setup.py install" in the ironic directory so everything got installed into the correct system place and then I could restart ironic-conductor.
It should all work in
develop mode, but clearly it doesn't, so in the interests of getting something up and going (and finish this blog post :) I did the quick solution and installed system-wide. Perhaps I'll circle back and work out why someday :)
Postscript #2:
When doing this, the deployment can fail for a number of reasons. To recover, you need to delete the enrolled node and start again once you've worked out what the problem is, and worked out how to fix it. To do that you need to do:
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic node-set-maintenance thenuc on
(venv)mrda@irony:~/src/python-ironicclient (master)$ ironic node-delete thenuc
Isn't it great that we can use names for nodes instead of UUIDs for most operations :)