cloudbase / cloudbase-init

Cross-platform instance initialization
http://openstack.org
Apache License 2.0
414 stars 150 forks source link

Multiple NIC password services failed from cloudstack #65

Open div8cn opened 3 years ago

div8cn commented 3 years ago

HI When the VM has multiple NICs, the password cannot be obtained from the correct meta data server

If a VM has >1 NIC, there will only be one NIC called Default NIC; Cloudstack will only store the vm password on the VR where the Default NIC is located But the meta data will be stored on the VR corresponding to all NICs;

The current verification method of cloudbase-init is:

As long as the meta data service-offering can be obtained from the dhcp server, it is considered that it can provide password services; https://github.com/cloudbase/cloudbase-init/blob/master/cloudbaseinit/metadata/services/cloudstack.py#L67

This is not correct

Password services should be individually verified

ader1990 commented 3 years ago

Hello,

Currently I have no CloudStack env to test a fix, but there might be a way to reuse the code from the AzureService to get the DHCP raw data and check if the VR is the correct one: https://github.com/cloudbase/cloudbase-init/blob/97295ba569c0e24fd08a37068d06df97c45dbb1f/cloudbaseinit/utils/dhcp.py#L124 https://github.com/cloudbase/cloudbase-init/blob/master/cloudbaseinit/metadata/services/azureservice.py#L68

I did not find any doc on how the DHCP lease creation is managed in CloudStack DHCP server implementation. If you have any documentation available on this, it would be great.

On Linux, this is the way to check if the dhcp server is the correct one:

cat /var/lib/dhclient/dhclient-eth0.leases | grep dhcp-server-identifier | tail -1

So reusing the Azure wireserver retrieval might lead to a proper implementation.

Another option would be to blindly iterate over all the DHCP servers like is done here, when trying to get/set password: https://github.com/cloudbase/cloudbase-init/blob/master/cloudbaseinit/metadata/services/cloudstack.py#L98

Thank you, Adrian Vladu

div8cn commented 3 years ago

I traverse all dhcp servers to obtain password information,It currently works well.

I have a test environment, I can provide code testing If necessary, please let me know, thanks!

ader1990 commented 3 years ago

If you could run on a Windows instance a Python interpreter or cloudbase-init changed to dump what dhcp.get_dhcp_options() returns, it would be great.

from cloudbaseinit.utils import dhcp

options = dhcp.get_dhcp_options()

print(options)
print(options.get('dhcp-server-identifier'))
div8cn commented 3 years ago

C:\Users\Administrator>C:\Cloudtools\Cloudbase-Init\Python\python Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AM D64)] on win32 Type "help", "copyright", "credits" or "license" for more information.

from cloudbaseinit.utils import dhcp options = dhcp.get_dhcp_options() Traceback (most recent call last): File "", line 1, in TypeError: get_dhcp_options() missing 1 required positional argument: 'dhcp_host '

ader1990 commented 3 years ago

dhcp_host is an optional argument, should not be the problem. Make sure you are using the latest installer, just in case that the Python version does not recognise a properly defined optional argument.

I have tried with the following code and it worked in my env:

from cloudbaseinit.utils import dhcp
options = dhcp.get_dhcp_options()
print(options)

If you can, put after this line a print(data), to see also the raw data: https://github.com/cloudbase/cloudbase-init/blob/97295ba569c0e24fd08a37068d06df97c45dbb1f/cloudbaseinit/utils/dhcp.py#L153

Thank you.

div8cn commented 3 years ago

from cloudbaseinit.utils import dhcp options = dhcp.get_dhcp_options() print(options) {53: b'\x02', 54: b'\xac\x10\x01\x01', 51: b'\xff\xff\xff\xff', 28: b'\xac\x10\x01\xff'}

print(options.get('dhcp-server-identifier')) None

ader1990 commented 3 years ago

from cloudbaseinit.utils import dhcp options = dhcp.get_dhcp_options() print(options) {53: b'\x02', 54: b'\xac\x10\x01\x01', 51: b'\xff\xff\xff\xff', 28: b'\xac\x10\x01\xff'}

print(options.get('dhcp-server-identifier')) None

Strange, those values look like there are no options received [updated: that is a valid DHCP answer]. I suppose that iterating through all the dhcp_servers will do the trick: https://github.com/cloudbase/cloudbase-init/blob/master/cloudbaseinit/metadata/services/cloudstack.py#L94.

Do you already a working code for the iterative approach?

Thank you, Adrian Vladu

ader1990 commented 3 years ago

from cloudbaseinit.utils import dhcp options = dhcp.get_dhcp_options() print(options) {53: b'\x02', 54: b'\xac\x10\x01\x01', 51: b'\xff\xff\xff\xff', 28: b'\xac\x10\x01\xff'}

print(options.get('dhcp-server-identifier')) None

I suppose you have multiple IPs, can you try to run the code with this change for each dhcp server? dhcp.get_dhcp_options(dhcp_host=<IP of dhcp server>)

div8cn commented 3 years ago

from cloudbaseinit.utils import dhcp options = dhcp.get_dhcp_options("10.1.1.1") print(options) {53: b'\x02', 54: b'\n\x01\x01\x01', 51: b'\xff\xff\xff\xff', 28: b'\n\x01\x01\x ff'} print(options.get('dhcp-server-identifier')) None

options = dhcp.get_dhcp_options("172.16.1.1") print(options) {53: b'\x02', 54: b'\xac\x10\x01\x01', 51: b'\xff\xff\xff\xff', 28: b'\xac\x10\x 01\xff'} print(options.get('dhcp-server-identifier')) None

172.16.1.1 is default nic