Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
protected String _agentHooksVmOnStopScript = "libvirt-vm-state-change.groovy";
protected String _agentHooksVmOnStopMethod = "onStop";

private static final String CONFIG_DRIVE_ISO_DISK_LABEL = "hdd";
private static final int CONFIG_DRIVE_ISO_DEVICE_ID = 4;

protected File _qemuSocketsPath;
private final String _qemuGuestAgentSocketName = "org.qemu.guest_agent.0";
Expand Down Expand Up @@ -2756,6 +2758,32 @@ protected KVMStoragePoolManager getPoolManager() {
return _storagePoolMgr;
}

public void detachAndAttachConfigDriveISO(final Connect conn, final String vmName) {
// detach and re-attach configdrive ISO
List<DiskDef> disks = getDisks(conn, vmName);
DiskDef configdrive = null;
for (DiskDef disk : disks) {
if (disk.getDeviceType() == DiskDef.DeviceType.CDROM && disk.getDiskLabel() == CONFIG_DRIVE_ISO_DISK_LABEL) {
configdrive = disk;
}
}
if (configdrive != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could invert the logic here to reduce block complexity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like your thinking @GutoVeronezi , but in this case that would leave a return in the middle of the method. I'd rather extract the block into an extra method.

try {
String result = attachOrDetachISO(conn, vmName, configdrive.getDiskPath(), false, CONFIG_DRIVE_ISO_DEVICE_ID);
if (result != null) {
s_logger.warn("Detach ConfigDrive ISO with result: " + result);
}
result = attachOrDetachISO(conn, vmName, configdrive.getDiskPath(), true, CONFIG_DRIVE_ISO_DEVICE_ID);
if (result != null) {
s_logger.warn("Attach ConfigDrive ISO with result: " + result);
}
} catch (final LibvirtException | InternalErrorException | URISyntaxException e) {
final String msg = "Detach and attach ConfigDrive ISO failed due to " + e.toString();
s_logger.warn(msg, e);
}
}
}

public synchronized String attachOrDetachISO(final Connect conn, final String vmName, String isoPath, final boolean isAttach, final Integer diskSeq) throws LibvirtException, URISyntaxException,
InternalErrorException {
final DiskDef iso = new DiskDef();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
import com.cloud.resource.ResourceWrapper;
import com.cloud.utils.Ternary;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VirtualMachine;
import com.google.common.base.Strings;

@ResourceWrapper(handles = MigrateCommand.class)
Expand Down Expand Up @@ -180,6 +181,10 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.

dconn = libvirtUtilitiesHelper.retrieveQemuConnection(destinationUri);

if (to.getType() == VirtualMachine.Type.User) {
libvirtComputingResource.detachAndAttachConfigDriveISO(conn, vmName);
}

//run migration in thread so we can monitor it
s_logger.info("Live migration of instance " + vmName + " initiated to destination host: " + dconn.getURI());
final ExecutorService executor = Executors.newFixedThreadPool(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ public Answer execute(final PlugNicCommand command, final LibvirtComputingResour
libvirtComputingResource.applyDefaultNetworkRulesOnNic(conn, vmName, vmId, nic, false, false);
}

if (vmType == VirtualMachine.Type.User) {
libvirtComputingResource.detachAndAttachConfigDriveISO(conn, vmName);
}

return new PlugNicAnswer(command, true, "success");
} catch (final LibvirtException e) {
final String msg = " Plug Nic failed due to " + e.toString();
Expand Down
16 changes: 15 additions & 1 deletion scripts/storage/secondary/createvolume.sh
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ create_from_file() {

}

copy_from_file() {
local tmpltfs=$1
local tmpltimg=$2
local tmpltname=$3

[ -n "$verbose" ] && echo "Copying to $tmpltfs/$tmpltname...could take a while" >&2
cp -rf $tmpltimg /$tmpltfs/$tmpltname
rm -rf $tmpltimg
}

tflag=
nflag=
fflag=
Expand Down Expand Up @@ -228,7 +238,11 @@ fi

imgsize=$(ls -l $tmpltimg2| awk -F" " '{print $5}')

create_from_file $tmpltfs $tmpltimg2 $tmpltname
if [ "$descr" = "configDrive" ] && [ "$Sflag" = "" ];then
copy_from_file $tmpltfs $tmpltimg2 $tmpltname
else
create_from_file $tmpltfs $tmpltimg2 $tmpltname
fi

touch /$tmpltfs/volume.properties
rollback_if_needed $tmpltfs $? "Failed to create volume.properties file"
Expand Down
19 changes: 11 additions & 8 deletions server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -630,20 +630,23 @@ private boolean enableStaticNat(long ipId, long vmId, long networkId, boolean is
}

protected void applyUserData(long vmId, Network network, Nic guestNic) throws ResourceUnavailableException {
UserVmVO vm = _vmDao.findById(vmId);
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
NicProfile nicProfile = new NicProfile(guestNic, network, null, null, null,
_networkModel.isSecurityGroupSupportedInNetwork(network),
_networkModel.getNetworkTag(template.getHypervisorType(), network));
VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm);
UserDataServiceProvider element = _networkModel.getUserDataUpdateProvider(network);
if (element == null) {
s_logger.error("Can't find network element for " + Service.UserData.getName() + " provider needed for UserData update");
} else {
boolean result = element.saveUserData(network, nicProfile, vmProfile);
if (!result) {
UserVmVO vm = _vmDao.findById(vmId);
try {
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
NicProfile nicProfile = new NicProfile(guestNic, network, null, null, null,
_networkModel.isSecurityGroupSupportedInNetwork(network),
_networkModel.getNetworkTag(template.getHypervisorType(), network));
VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm);
if (!element.saveUserData(network, nicProfile, vmProfile)) {
s_logger.error("Failed to update userdata for vm " + vm + " and nic " + guestNic);
}
} catch (Exception e) {
s_logger.error("Failed to update userdata for vm " + vm + " and nic " + guestNic + " due to " + e.getMessage(), e);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions setup/bindir/cloud-set-guest-sshkey-configdrive.in
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ mountdir=$(mktemp -d)
# If lable name is other than config, please change the below line as required
DefaultDisk=/dev/disk/by-label/config-2

SSHKey_File=$mountdir/cloudstack/metadata/public_keys.txt
SSHKey_File=$mountdir/cloudstack/metadata/public-keys.txt
keys_received=0

function prepare_mount
Expand All @@ -44,7 +44,7 @@ function prepare_mount
if [ -e $DefaultDisk ]; then
Disk=$DefaultDisk
else
BLOCK_DEVICE=$(blkid -t LABEL='config' /dev/hd? /dev/sd? /dev/xvd? /dev/vd? -o device)
BLOCK_DEVICE=$(blkid -t LABEL='config-2' /dev/hd? /dev/sd? /dev/xvd? /dev/vd? -o device)
if [ -n $BLOCK_DEVICE ]; then
Disk=$BLOCK_DEVICE
else
Expand Down
32 changes: 20 additions & 12 deletions test/integration/component/test_configdrive.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
Hypervisor, Template)
from marvin.lib.common import (get_domain,
get_template,
get_zone, get_test_template,
get_zone,
get_test_template,
is_config_suitable)
from marvin.lib.utils import random_gen
# Import System Modules
Expand Down Expand Up @@ -104,12 +105,12 @@ def __init__(self):
self.services = {
"test_templates": {
"kvm": {
"name": "Centos-5.5-configdrive",
"displaytext": "ConfigDrive enabled CentOS",
"name": "Centos-5.5-sshkey-and-configdrive",
"displaytext": "SSHkey and ConfigDrive enabled CentOS",
"format": "qcow2",
"hypervisor": "kvm",
"ostype": "CentOS 5.5 (64-bit)",
"url": "http://people.apache.org/~fmaximus/centos55-extended.qcow2.bz2",
"url": "http://people.apache.org/~weizhou/centos55-sshkey-configdrive.qcow2.bz2",
"requireshvm": "False",
"ispublic": "True",
"isextractable": "True"
Expand Down Expand Up @@ -653,8 +654,7 @@ def given_template_password_enabled_is(self, new_state):
orig_state = self.template.passwordenabled
self.debug("Updating guest VM template to password enabled "
"from %s to %s" % (orig_state, new_state))
if orig_state != new_state:
self.update_template(passwordenabled=new_state)
self.update_template(passwordenabled=new_state)
self.assertEqual(self.template.passwordenabled, new_state,
"Guest VM template is not password enabled")
return orig_state
Expand Down Expand Up @@ -850,7 +850,7 @@ def then_config_drive_is_as_expected(self, vm,

self.debug("SSHing into the VM %s" % vm.name)

ssh = self.ssh_into_VM(vm, public_ip, reconnect=reconnect)
ssh = self.ssh_into_VM(vm, public_ip, reconnect=reconnect, keypair=vm.key_pair)

d = {x.name: x for x in ssh.logger.handlers}
ssh.logger.handlers = list(d.values())
Expand Down Expand Up @@ -974,6 +974,7 @@ def plug_nic(self, vm, network):
vm.add_nic(self.api_client, network.id)
self.debug("Added NIC in VM with ID - %s and network with ID - %s"
% (vm.id, network.id))
vm.password_test = ConfigDriveUtils.PasswordTest(expect_pw=False)

def unplug_nic(self, vm, network):
nic = self._find_nic(vm, network)
Expand Down Expand Up @@ -1530,12 +1531,14 @@ def ssh_into_VM(self, vm, public_ip, reconnect=True,
self.debug("SSH into VM with ID - %s on public IP address - %s" %
(vm.id, public_ip.ipaddress.ipaddress))
tries = 1 if negative_test else 3
private_key_file_location = keypair.private_key_file if keypair else None

@retry(tries=tries)
def retry_ssh():
ssh_client = vm.get_ssh_client(
ipaddress=public_ip.ipaddress.ipaddress,
reconnect=reconnect,
keyPairFileLocation=private_key_file_location,
retries=3 if negative_test else 30
)
self.debug("Successful to SSH into VM with ID - %s on "
Expand Down Expand Up @@ -1702,6 +1705,7 @@ def migrate_VM(self, vm):
"%s to Host: %s" % (vm.id, host.id))
try:
vm.migrate(self.api_client, hostid=host.id)
vm.password_test = ConfigDriveUtils.PasswordTest(expect_pw=False)
except Exception as e:
self.fail("Failed to migrate instance, %s" % e)
self.debug("Migrated VM with ID: "
Expand Down Expand Up @@ -1917,7 +1921,8 @@ def test_configdrive_isolated_network(self):
# =====================================================================
self.debug("+++ Scenario: "
"update userdata and reset password after migrate")
self.migrate_VM(vm1)
host = self.migrate_VM(vm1)
vm1.hostname = host.name
self.then_config_drive_is_as_expected(vm1, public_ip_1, metadata=True)
self.debug("Updating userdata after migrating VM - %s" % vm1.name)
self.update_and_validate_userdata(vm1, "hello after migrate",
Expand Down Expand Up @@ -1955,7 +1960,7 @@ def test_configdrive_isolated_network(self):
# =====================================================================
self.debug("+++ Scenario: "
"Update Userdata on a VM that is not password enabled")
self.update_template(passwordenabled=False)
self.given_template_password_enabled_is(False)
vm1 = self.when_I_deploy_a_vm_with_keypair_in(network1)

public_ip_1 = \
Expand Down Expand Up @@ -2112,7 +2117,8 @@ def test_configdrive_vpc_network(self):
# =====================================================================
self.debug("+++ Scenario: "
"update userdata and reset password after migrate")
self.migrate_VM(vm)
host = self.migrate_VM(vm)
vm.hostname = host.name
self.then_config_drive_is_as_expected(vm, public_ip_1, metadata=True)
self.update_and_validate_userdata(vm, "hello migrate", public_ip_1)

Expand Down Expand Up @@ -2150,7 +2156,7 @@ def test_configdrive_vpc_network(self):
self.debug("+++ Scenario: "
"Update Userdata on a VM that is not password enabled")

self.update_template(passwordenabled=False)
self.given_template_password_enabled_is(False)

vm = self.when_I_deploy_a_vm(network1,
keypair=self.keypair.name)
Expand Down Expand Up @@ -2285,7 +2291,7 @@ def test_configdrive_shared_network(self):
self.delete(vm1, expunge=True)

self.given_config_drive_provider_is("Enabled")
self.update_template(passwordenabled=False)
self.given_template_password_enabled_is(False)

vm1 = self.create_VM(
[shared_network.network],
Expand Down Expand Up @@ -2362,6 +2368,7 @@ def test_configdrive_isolated_network_hypervisor_hostname_exposed(self):
self.debug("+++Deploy VM in the created Isolated network "
"with user data provider as configdrive")

self.given_template_password_enabled_is(True)
vm1 = self.when_I_deploy_a_vm(network1)

public_ip_1 = self.when_I_create_a_static_nat_ip_to(vm1, network1)
Expand Down Expand Up @@ -2476,6 +2483,7 @@ def test_configdrive_vpc_network_verify_metadata(self):
# =====================================================================
self.debug("+++ Scenario: "
"Deploy VM in the Tier 1 with user data")
self.given_template_password_enabled_is(True)
vm = self.when_I_deploy_a_vm(network1)
public_ip_1 = self.when_I_create_a_static_nat_ip_to(vm, network1)

Expand Down