diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java index 4d715898a75..d6c215f42f0 100755 --- a/api/src/com/cloud/offering/ServiceOffering.java +++ b/api/src/com/cloud/offering/ServiceOffering.java @@ -77,6 +77,11 @@ public interface ServiceOffering extends InfrastructureEntity, InternalIdentity, */ boolean getLimitCpuUse(); + /** + * @return Does this service plan support Volatile VM that is, discard VM's root disk and create a new one on reboot? + */ + boolean getVolatileVm(); + /** * @return the rate in megabits per sec to which a VM's network interface is throttled to */ diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index cd7d700d2b5..35a11dd7a53 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -218,6 +218,7 @@ public class ApiConstants { public static final String VM_LIMIT = "vmlimit"; public static final String VM_TOTAL = "vmtotal"; public static final String VNET = "vnet"; + public static final String IS_VOLATILE = "isvolatile"; public static final String VOLUME_ID = "volumeid"; public static final String ZONE_ID = "zoneid"; public static final String ZONE_NAME = "zonename"; diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index ee1e1b20bfc..e915c48e9b6 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -59,6 +59,9 @@ public class CreateServiceOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.LIMIT_CPU_USE, type=CommandType.BOOLEAN, description="restrict the CPU usage to committed service offering") private Boolean limitCpuUse; + @Parameter(name=ApiConstants.IS_VOLATILE, type=CommandType.BOOLEAN, description="true if the virtual machine needs to be volatile so that on every reboot of VM, original root disk is dettached then destroyed and a fresh root disk is created and attached to VM") + private Boolean isVolatile; + @Parameter(name=ApiConstants.STORAGE_TYPE, type=CommandType.STRING, description="the storage type of the service offering. Values are local and shared.") private String storageType; @@ -106,11 +109,15 @@ public class CreateServiceOfferingCmd extends BaseCmd { } public Boolean getOfferHa() { - return offerHa; + return offerHa == null ? false : offerHa; } public Boolean GetLimitCpuUse() { - return limitCpuUse; + return limitCpuUse == null ? false : limitCpuUse; + } + + public Boolean getVolatileVm() { + return isVolatile == null ? false : isVolatile; } public String getStorageType() { diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 5c1b0d58c6f..7193928ca33 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -72,6 +72,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @param localStorageRequired * @param offerHA * @param domainId + * @param volatileVm * @param hostTag * @param networkRate * TODO @@ -80,7 +81,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @return ID */ ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, - boolean offerHA, boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate); + boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate); /** * Creates a new disk offering diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index b886bedbc48..cf3a9080a1f 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1777,14 +1777,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } Boolean offerHA = cmd.getOfferHa(); - if (offerHA == null) { - offerHA = false; - } - Boolean limitCpuUse = cmd.GetLimitCpuUse(); - if (limitCpuUse == null) { - limitCpuUse = false; - } + Boolean volatileVm = cmd.getVolatileVm(); String vmTypeString = cmd.getSystemVmType(); VirtualMachine.Type vmType = null; @@ -1811,15 +1805,15 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber.intValue(), memory.intValue(), cpuSpeed.intValue(), cmd.getDisplayText(), - localStorageRequired, offerHA, limitCpuUse, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate()); + localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate()); } @Override @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CREATE, eventDescription = "creating service offering") public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_type, String name, int cpu, int ramSize, int speed, String displayText, - boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate) { + boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) { tags = cleanupTags(tags); - ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, displayText, localStorageRequired, false, tags, isSystem, vm_type, + ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, localStorageRequired, false, tags, isSystem, vm_type, domainId, hostTag); if ((offering = _serviceOfferingDao.persist(offering)) != null) { diff --git a/server/src/com/cloud/migration/ServiceOffering21VO.java b/server/src/com/cloud/migration/ServiceOffering21VO.java index fdec30e3b8a..d07be6462f1 100644 --- a/server/src/com/cloud/migration/ServiceOffering21VO.java +++ b/server/src/com/cloud/migration/ServiceOffering21VO.java @@ -169,5 +169,10 @@ public class ServiceOffering21VO extends DiskOffering21VO implements ServiceOffe return null; } + @Override + public boolean getVolatileVm() { + return false; + } + } diff --git a/server/src/com/cloud/service/ServiceOfferingVO.java b/server/src/com/cloud/service/ServiceOfferingVO.java index c199a86afd1..7be939c3a15 100755 --- a/server/src/com/cloud/service/ServiceOfferingVO.java +++ b/server/src/com/cloud/service/ServiceOfferingVO.java @@ -53,6 +53,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering @Column(name="limit_cpu_use") private boolean limitCpuUse; + @Column(name="is_volatile") + private boolean volatileVm; + @Column(name="host_tag") private String hostTag; @@ -78,11 +81,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.multicastRateMbps = multicastRateMbps; this.offerHA = offerHA; this.limitCpuUse = false; + this.volatileVm = false; this.default_use = defaultUse; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); } - public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId) { + public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId) { super(name, displayText, false, tags, recreatable, useLocalStorage, systemUse, true, domainId); this.cpu = cpu; this.ramSize = ramSize; @@ -91,11 +95,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.multicastRateMbps = multicastRateMbps; this.offerHA = offerHA; this.limitCpuUse = limitCpuUse; + this.volatileVm = volatileVm; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); } - public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) { - this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId); + public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) { + this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId); this.hostTag = hostTag; } @@ -189,13 +194,18 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public String getSystemVmType(){ return vm_type; } + + public void setSortKey(int key) { + sortKey = key; + } + + public int getSortKey() { + return sortKey; + } - public void setSortKey(int key) { - sortKey = key; + @Override + public boolean getVolatileVm() { + return volatileVm; } - - public int getSortKey() { - return sortKey; - } - + } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index df976099f1d..ea25c663428 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2672,6 +2672,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _accountMgr.checkAccess(caller, null, true, vmInstance); + // If the VM is Volatile in nature, on reboot discard the VM's root disk and create a new root disk for it: by calling restoreVM + long serviceOfferingId = vmInstance.getServiceOfferingId(); + ServiceOfferingVO offering = _serviceOfferingDao.findById(serviceOfferingId); + if(offering.getVolatileVm()){ + return restoreVMInternal(caller, vmInstance); + } + return rebootVirtualMachine(UserContext.current().getCallerUserId(), vmId); } @@ -4789,19 +4796,27 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // Input validation Account caller = UserContext.current().getCaller(); Long userId = UserContext.current().getCallerUserId(); - UserVO user = _userDao.findById(userId); - boolean needRestart = false; long vmId = cmd.getVmId(); UserVmVO vm = _vmDao.findById(vmId); if (vm == null) { - InvalidParameterValueException ex = new InvalidParameterValueException( - "Cann not find VM with ID " + vmId); + InvalidParameterValueException ex = new InvalidParameterValueException("Cannot find VM with ID " + vmId); ex.addProxyObject(vm, vmId, "vmId"); throw ex; } + return restoreVMInternal(caller, vm); + } + + public UserVm restoreVMInternal(Account caller, UserVmVO vm){ + + Long userId = caller.getId(); Account owner = _accountDao.findById(vm.getAccountId()); + UserVO user = _userDao.findById(userId); + long vmId = vm.getId(); + boolean needRestart = false; + + // Input validation if (owner == null) { throw new InvalidParameterValueException("The owner of " + vm + " does not exist: " + vm.getAccountId()); @@ -4816,7 +4831,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use && vm.getState() != VirtualMachine.State.Stopped) { throw new CloudRuntimeException( "Vm " - + vmId + + vm.getUuid() + " currently in " + vm.getState() + " state, restore vm can only execute when VM in Running or Stopped"); @@ -4829,13 +4844,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use List rootVols = _volsDao.findByInstance(vmId); if (rootVols.isEmpty()) { InvalidParameterValueException ex = new InvalidParameterValueException( - "Can not find root volume for VM " + vmId); + "Can not find root volume for VM " + vm.getUuid()); ex.addProxyObject(vm, vmId, "vmId"); throw ex; } VolumeVO root = rootVols.get(0); - long templateId = root.getTemplateId(); + Long templateId = root.getTemplateId(); + if(templateId == null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Currently there is no support to reset a vm that is deployed using ISO " + vm.getUuid()); + ex.addProxyObject(vm, vmId, "vmId"); + throw ex; + } + VMTemplateVO template = _templateDao.findById(templateId); if (template == null) { InvalidParameterValueException ex = new InvalidParameterValueException( @@ -4849,7 +4870,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use try { _itMgr.stop(vm, user, caller); } catch (ResourceUnavailableException e) { - s_logger.debug("Stop vm " + vmId + " failed", e); + s_logger.debug("Stop vm " + vm.getUuid() + " failed", e); CloudRuntimeException ex = new CloudRuntimeException( "Stop vm failed for specified vmId"); ex.addProxyObject(vm, vmId, "vmId"); @@ -4874,7 +4895,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use try { _itMgr.start(vm, null, user, caller); } catch (Exception e) { - s_logger.debug("Unable to start VM " + vmId, e); + s_logger.debug("Unable to start VM " + vm.getUuid(), e); CloudRuntimeException ex = new CloudRuntimeException( "Unable to start VM with specified id" + e.getMessage()); ex.addProxyObject(vm, vmId, "vmId"); @@ -4882,9 +4903,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - s_logger.debug("Restore VM " + vmId + " with template " + s_logger.debug("Restore VM " + vm.getUuid() + " with template " + root.getTemplateId() + " successfully"); return vm; + } @Override diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java new file mode 100755 index 00000000000..46069ede5d6 --- /dev/null +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -0,0 +1,148 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.vm; + +import java.util.List; + +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.log4j.Logger; +import org.junit.Test; +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.storage.StorageManager; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.dao.UserVmDao; + +import static org.mockito.Mockito.*; + +public class UserVmManagerTest { + + @Spy UserVmManagerImpl _userVmMgr = new UserVmManagerImpl(); + @Mock VirtualMachineManager _itMgr; + @Mock StorageManager _storageMgr; + @Mock Account account; + @Mock AccountManager _accountMgr; + @Mock AccountDao _accountDao; + @Mock UserDao _userDao; + @Mock UserVmDao _vmDao; + @Mock VMTemplateDao _templateDao; + @Mock VolumeDao _volsDao; + @Mock RestoreVMCmd restoreVMCmd; + @Mock AccountVO accountMock; + @Mock UserVO userMock; + @Mock UserVmVO vmMock; + @Mock VMTemplateVO templateMock; + @Mock VolumeVO volumeMock; + @Mock List rootVols; + @Before + public void setup(){ + MockitoAnnotations.initMocks(this); + + _userVmMgr._vmDao = _vmDao; + _userVmMgr._templateDao = _templateDao; + _userVmMgr._volsDao = _volsDao; + _userVmMgr._itMgr = _itMgr; + _userVmMgr._storageMgr = _storageMgr; + _userVmMgr._accountDao = _accountDao; + _userVmMgr._userDao = _userDao; + + doReturn(3L).when(account).getId(); + doReturn(8L).when(vmMock).getAccountId(); + when(_accountDao.findById(anyLong())).thenReturn(accountMock); + when(_userDao.findById(anyLong())).thenReturn(userMock); + doReturn(Account.State.enabled).when(account).getState(); + when(vmMock.getId()).thenReturn(314L); + + } + + // VM state not in running/stopped case + @Test(expected=CloudRuntimeException.class) + public void testRestoreVMF1() throws ResourceAllocationException { + + when(_vmDao.findById(anyLong())).thenReturn(vmMock); + when(_templateDao.findById(anyLong())).thenReturn(templateMock); + doReturn(VirtualMachine.State.Error).when(vmMock).getState(); + _userVmMgr.restoreVMInternal(account, vmMock); + } + + // when VM is in stopped state + @Test + public void testRestoreVMF2() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, + ConcurrentOperationException, ResourceAllocationException { + + doReturn(VirtualMachine.State.Stopped).when(vmMock).getState(); + when(_vmDao.findById(anyLong())).thenReturn(vmMock); + when(_volsDao.findByInstance(anyLong())).thenReturn(rootVols); + doReturn(false).when(rootVols).isEmpty(); + when(rootVols.get(eq(0))).thenReturn(volumeMock); + doReturn(3L).when(volumeMock).getTemplateId(); + when(_templateDao.findById(anyLong())).thenReturn(templateMock); + when(_storageMgr.allocateDuplicateVolume(volumeMock, null)).thenReturn(volumeMock); + doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong()); + when(volumeMock.getId()).thenReturn(3L); + doNothing().when(_volsDao).detachVolume(anyLong()); + when(_storageMgr.destroyVolume(volumeMock)).thenReturn(true); + + _userVmMgr.restoreVMInternal(account, vmMock); + + } + + // when VM is in running state + @Test + public void testRestoreVMF3() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, + ConcurrentOperationException, ResourceAllocationException { + + doReturn(VirtualMachine.State.Running).when(vmMock).getState(); + when(_vmDao.findById(anyLong())).thenReturn(vmMock); + when(_volsDao.findByInstance(anyLong())).thenReturn(rootVols); + doReturn(false).when(rootVols).isEmpty(); + when(rootVols.get(eq(0))).thenReturn(volumeMock); + doReturn(3L).when(volumeMock).getTemplateId(); + when(_templateDao.findById(anyLong())).thenReturn(templateMock); + when(_itMgr.stop(vmMock, userMock, account)).thenReturn(true); + when(_itMgr.start(vmMock, null, userMock, account)).thenReturn(vmMock); + when(_storageMgr.allocateDuplicateVolume(volumeMock, null)).thenReturn(volumeMock); + doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong()); + when(volumeMock.getId()).thenReturn(3L); + doNothing().when(_volsDao).detachVolume(anyLong()); + when(_storageMgr.destroyVolume(volumeMock)).thenReturn(true); + + _userVmMgr.restoreVMInternal(account, vmMock); + + } + +} \ No newline at end of file diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 180138ac136..e93b2a14c52 100644 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -433,7 +433,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA, - boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate) { + boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) { // TODO Auto-generated method stub return null; } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 65add75294b..0335f2a0781 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -23,4 +23,7 @@ ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `max_hosts_per_cluster` UPDATE `cloud`.`hypervisor_capabilities` SET `max_hosts_per_cluster`=32 WHERE `hypervisor_type`='VMware'; INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_hosts_per_cluster) VALUES ('VMware', '5.1', 128, 0, 32); DELETE FROM `cloud`.`configuration` where name='vmware.percluster.host.max'; -INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xen.nics.max', '7', 'Maximum allowed nics for Vms created on Xen'); \ No newline at end of file +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xen.nics.max', '7', 'Maximum allowed nics for Vms created on Xen'); + + +ALTER TABLE `cloud`.`service_offering` ADD COLUMN `is_volatile` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the vm needs to be volatile, i.e., on every reboot of vm from API root disk is discarded and creates a new root disk';