mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-9813: Extending Config Drive support (#2097)
Extending Config Drive support * Added support for VMware * Build configdrive.iso on ssvm * Added support for VPC and Isolated Networks * Moved implementation to new Service Provider * UI fix: add support for urlencoded userdata * Add support for building systemvm behind a proxy Co-Authored-By: Raf Smeets <raf.smeets@nuagenetworks.net> Co-Authored-By: Frank Maximus <frank.maximus@nuagenetworks.net> Co-Authored-By: Sigert Goeminne <sigert.goeminne@nuagenetworks.net>
This commit is contained in:
parent
7ca4582a85
commit
b176648f90
@ -142,6 +142,8 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
|
|||||||
public static final Provider GloboDns = new Provider("GloboDns", true);
|
public static final Provider GloboDns = new Provider("GloboDns", true);
|
||||||
// add Big Switch Bcf Provider
|
// add Big Switch Bcf Provider
|
||||||
public static final Provider BigSwitchBcf = new Provider("BigSwitchBcf", false);
|
public static final Provider BigSwitchBcf = new Provider("BigSwitchBcf", false);
|
||||||
|
//Add ConfigDrive provider
|
||||||
|
public static final Provider ConfigDrive = new Provider("ConfigDrive", false);
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final boolean isExternal;
|
private final boolean isExternal;
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package com.cloud.network;
|
package com.cloud.network;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -48,6 +50,28 @@ import org.apache.cloudstack.framework.config.ConfigKey;
|
|||||||
* participants in the orchestration can use this interface to query the data.
|
* participants in the orchestration can use this interface to query the data.
|
||||||
*/
|
*/
|
||||||
public interface NetworkModel {
|
public interface NetworkModel {
|
||||||
|
String METATDATA_DIR = "metadata";
|
||||||
|
String USERDATA_DIR = "userdata";
|
||||||
|
String USERDATA_FILE = "user_data";
|
||||||
|
String PASSWORD_DIR = "password";
|
||||||
|
String PASSWORD_FILE = "vm_password";
|
||||||
|
String PASSWORD_CHECKSUM_FILE = "vm-password-md5checksum";
|
||||||
|
String SERVICE_OFFERING_FILE = "service-offering";
|
||||||
|
String AVAILABILITY_ZONE_FILE = "availability-zone";
|
||||||
|
String LOCAL_HOSTNAME_FILE = "local-hostname";
|
||||||
|
String INSTANCE_ID_FILE = "instance-id";
|
||||||
|
String VM_ID_FILE = "vm-id";
|
||||||
|
String PUBLIC_KEYS_FILE = "public-keys";
|
||||||
|
String CLOUD_IDENTIFIER_FILE = "cloud-identifier";
|
||||||
|
int CONFIGDATA_DIR = 0;
|
||||||
|
int CONFIGDATA_FILE = 1;
|
||||||
|
int CONFIGDATA_CONTENT = 2;
|
||||||
|
ImmutableMap<String, String> openStackFileMapping = ImmutableMap.of(
|
||||||
|
AVAILABILITY_ZONE_FILE, "availability_zone",
|
||||||
|
LOCAL_HOSTNAME_FILE, "hostname",
|
||||||
|
VM_ID_FILE, "uuid",
|
||||||
|
INSTANCE_ID_FILE, "name"
|
||||||
|
);
|
||||||
|
|
||||||
static final ConfigKey<Integer> MACIdentifier = new ConfigKey<Integer>("Advanced",Integer.class, "mac.identifier", "0",
|
static final ConfigKey<Integer> MACIdentifier = new ConfigKey<Integer>("Advanced",Integer.class, "mac.identifier", "0",
|
||||||
"This value will be used while generating the mac addresses for isolated and shared networks. The hexadecimal equivalent value will be present at the 2nd octet of the mac address. Default value is null which means this feature is disabled.Its scope is global.", true, ConfigKey.Scope.Global);
|
"This value will be used while generating the mac addresses for isolated and shared networks. The hexadecimal equivalent value will be present at the 2nd octet of the mac address. Default value is null which means this feature is disabled.Its scope is global.", true, ConfigKey.Scope.Global);
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
||||||
import org.apache.cloudstack.api.ACL;
|
import org.apache.cloudstack.api.ACL;
|
||||||
@ -47,7 +49,6 @@ import org.apache.cloudstack.api.response.UserVmResponse;
|
|||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import com.cloud.event.EventTypes;
|
import com.cloud.event.EventTypes;
|
||||||
import com.cloud.exception.ConcurrentOperationException;
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||||
import org.apache.cloudstack.api.ACL;
|
import org.apache.cloudstack.api.ACL;
|
||||||
@ -35,7 +37,6 @@ import org.apache.cloudstack.api.response.GuestOSResponse;
|
|||||||
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import com.cloud.exception.InsufficientCapacityException;
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
|||||||
55
core/src/com/cloud/agent/api/AttachIsoAnswer.java
Normal file
55
core/src/com/cloud/agent/api/AttachIsoAnswer.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// 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.agent.api;
|
||||||
|
|
||||||
|
|
||||||
|
public class AttachIsoAnswer extends Answer {
|
||||||
|
private Integer deviceKey;
|
||||||
|
|
||||||
|
|
||||||
|
public AttachIsoAnswer(AttachIsoCommand cmd, String result) {
|
||||||
|
super(cmd, false, result);
|
||||||
|
this.deviceKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachIsoAnswer(AttachIsoCommand cmd, Integer deviceId) {
|
||||||
|
super(cmd);
|
||||||
|
this.deviceKey = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachIsoAnswer(AttachIsoCommand cmd) {
|
||||||
|
super(cmd);
|
||||||
|
this.deviceKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachIsoAnswer(AttachIsoCommand command, boolean success, String details) {
|
||||||
|
super(command,success,details);
|
||||||
|
this.deviceKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachIsoAnswer(Command command, Exception e) {
|
||||||
|
super(command, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDeviceKey() {
|
||||||
|
return deviceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceKey(Integer deviceKey) {
|
||||||
|
this.deviceKey = deviceKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,14 +25,22 @@ public class AttachIsoCommand extends Command {
|
|||||||
private String storeUrl;
|
private String storeUrl;
|
||||||
private String isoPath;
|
private String isoPath;
|
||||||
private boolean attach;
|
private boolean attach;
|
||||||
|
private Integer deviceKey;
|
||||||
|
private boolean force;
|
||||||
|
|
||||||
protected AttachIsoCommand() {
|
protected AttachIsoCommand() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttachIsoCommand(String vmName, String isoPath, boolean attach) {
|
public AttachIsoCommand(String vmName, String isoPath, boolean attach, Integer deviceKey, boolean force) {
|
||||||
this.vmName = vmName;
|
this.vmName = vmName;
|
||||||
this.isoPath = isoPath;
|
this.isoPath = isoPath;
|
||||||
this.attach = attach;
|
this.attach = attach;
|
||||||
|
this.deviceKey = deviceKey;
|
||||||
|
this.force = force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachIsoCommand(String vmName, String isoPath, boolean attach) {
|
||||||
|
this(vmName, isoPath, attach, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -52,6 +60,10 @@ public class AttachIsoCommand extends Command {
|
|||||||
return attach;
|
return attach;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAttach(boolean attach) {
|
||||||
|
this.attach = attach;
|
||||||
|
}
|
||||||
|
|
||||||
public String getStoreUrl() {
|
public String getStoreUrl() {
|
||||||
return storeUrl;
|
return storeUrl;
|
||||||
}
|
}
|
||||||
@ -59,4 +71,16 @@ public class AttachIsoCommand extends Command {
|
|||||||
public void setStoreUrl(String url) {
|
public void setStoreUrl(String url) {
|
||||||
storeUrl = url;
|
storeUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDeviceKey(Integer deviceKey) {
|
||||||
|
this.deviceKey = deviceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDeviceKey() {
|
||||||
|
return deviceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForce() {
|
||||||
|
return force;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,78 @@
|
|||||||
|
//
|
||||||
|
// 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.agent.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
|
||||||
|
public class HandleConfigDriveIsoCommand extends Command {
|
||||||
|
|
||||||
|
String isoFile;
|
||||||
|
List<String[]> vmData;
|
||||||
|
String configDriveLabel;
|
||||||
|
boolean create = false;
|
||||||
|
private boolean update = false;
|
||||||
|
private DataStoreTO destStore;
|
||||||
|
|
||||||
|
public HandleConfigDriveIsoCommand(List<String[]> vmData, String label, DataStoreTO destStore, String isoFile, boolean create, boolean update) {
|
||||||
|
this.vmData = vmData;
|
||||||
|
this.configDriveLabel = label;
|
||||||
|
this.create = create;
|
||||||
|
this.update = update;
|
||||||
|
this.destStore = destStore;
|
||||||
|
|
||||||
|
|
||||||
|
this.isoFile = isoFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean executeInSequence() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String[]> getVmData() {
|
||||||
|
return vmData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVmData(List<String[]> vmData) {
|
||||||
|
this.vmData = vmData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCreate() {
|
||||||
|
return create;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConfigDriveLabel() {
|
||||||
|
return configDriveLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataStoreTO getDestStore() {
|
||||||
|
return destStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIsoFile() {
|
||||||
|
return isoFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUpdate() {
|
||||||
|
return update;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,16 +19,24 @@
|
|||||||
|
|
||||||
package org.apache.cloudstack.api.agent.test;
|
package org.apache.cloudstack.api.agent.test;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.AttachIsoCommand;
|
||||||
|
import com.cloud.agent.api.Command;
|
||||||
|
import com.cloud.serializer.GsonHelper;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import com.cloud.agent.api.AttachIsoCommand;
|
|
||||||
|
|
||||||
public class AttachIsoCommandTest {
|
public class AttachIsoCommandTest {
|
||||||
AttachIsoCommand aic = new AttachIsoCommand("vmname", "isopath", false);
|
|
||||||
|
private static final Gson s_gson = GsonHelper.getGson();
|
||||||
|
|
||||||
|
AttachIsoCommand aic = new AttachIsoCommand("vmname", "isopath", false, 1, true);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetVmName() {
|
public void testGetVmName() {
|
||||||
@ -80,4 +88,17 @@ public class AttachIsoCommandTest {
|
|||||||
b = aic.getWait();
|
b = aic.getWait();
|
||||||
assertEquals(b, 0);
|
assertEquals(b, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerialization() {
|
||||||
|
AttachIsoCommand after = serializeAndDeserialize(aic);
|
||||||
|
Assert.assertEquals(aic, after);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Command> T serializeAndDeserialize(T command) {
|
||||||
|
final String json = s_gson.toJson(new Command[] {command});
|
||||||
|
Command[] forwardedCommands = s_gson.fromJson(json, Command[].class);
|
||||||
|
return (T) forwardedCommands[0];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,7 +52,7 @@ public interface VirtualMachineManager extends Manager {
|
|||||||
static final ConfigKey<Boolean> ExecuteInSequence = new ConfigKey<Boolean>("Advanced", Boolean.class, "execute.in.sequence.hypervisor.commands", "false",
|
static final ConfigKey<Boolean> ExecuteInSequence = new ConfigKey<Boolean>("Advanced", Boolean.class, "execute.in.sequence.hypervisor.commands", "false",
|
||||||
"If set to true, start, stop, reboot, copy and migrate commands will be serialized on the agent side. If set to false the commands are executed in parallel. Default value is false.", false);
|
"If set to true, start, stop, reboot, copy and migrate commands will be serialized on the agent side. If set to false the commands are executed in parallel. Default value is false.", false);
|
||||||
|
|
||||||
static final ConfigKey<String> VmConfigDriveLabel = new ConfigKey<String>("Hidden", String.class, "vm.configdrive.label", "config",
|
static final ConfigKey<String> VmConfigDriveLabel = new ConfigKey<String>("Hidden", String.class, "vm.configdrive.label", "config-2",
|
||||||
"The default label name for the config drive", false);
|
"The default label name for the config drive", false);
|
||||||
|
|
||||||
public interface Topics {
|
public interface Topics {
|
||||||
|
|||||||
@ -41,7 +41,6 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
@ -69,7 +68,6 @@ import org.w3c.dom.Node;
|
|||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
|
||||||
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||||
@ -2251,16 +2249,15 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
DiskDef.DiskBus diskBusTypeData = (diskBusType == DiskDef.DiskBus.SCSI) ? diskBusType : DiskDef.DiskBus.VIRTIO;
|
DiskDef.DiskBus diskBusTypeData = (diskBusType == DiskDef.DiskBus.SCSI) ? diskBusType : DiskDef.DiskBus.VIRTIO;
|
||||||
|
|
||||||
final DiskDef disk = new DiskDef();
|
final DiskDef disk = new DiskDef();
|
||||||
|
int devId = volume.getDiskSeq().intValue();
|
||||||
if (volume.getType() == Volume.Type.ISO) {
|
if (volume.getType() == Volume.Type.ISO) {
|
||||||
if (volPath == null) {
|
if (volPath == null) {
|
||||||
/* Add iso as placeholder */
|
/* Add iso as placeholder */
|
||||||
disk.defISODisk(null);
|
disk.defISODisk(null, devId);
|
||||||
} else {
|
} else {
|
||||||
disk.defISODisk(volPath);
|
disk.defISODisk(volPath, devId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final int devId = volume.getDiskSeq().intValue();
|
|
||||||
|
|
||||||
if (diskBusType == DiskDef.DiskBus.SCSI ) {
|
if (diskBusType == DiskDef.DiskBus.SCSI ) {
|
||||||
disk.setQemuDriver(true);
|
disk.setQemuDriver(true);
|
||||||
disk.setDiscard(DiscardType.UNMAP);
|
disk.setDiscard(DiscardType.UNMAP);
|
||||||
@ -2390,9 +2387,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
return _storagePoolMgr;
|
return _storagePoolMgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized String attachOrDetachISO(final Connect conn, final String vmName, String isoPath, final boolean isAttach) throws LibvirtException, URISyntaxException,
|
public synchronized String attachOrDetachISO(final Connect conn, final String vmName, String isoPath, final boolean isAttach, final Integer diskSeq) throws LibvirtException, URISyntaxException,
|
||||||
InternalErrorException {
|
InternalErrorException {
|
||||||
String isoXml = null;
|
final DiskDef iso = new DiskDef();
|
||||||
if (isoPath != null && isAttach) {
|
if (isoPath != null && isAttach) {
|
||||||
final int index = isoPath.lastIndexOf("/");
|
final int index = isoPath.lastIndexOf("/");
|
||||||
final String path = isoPath.substring(0, index);
|
final String path = isoPath.substring(0, index);
|
||||||
@ -2401,20 +2398,17 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
final KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
|
final KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
|
||||||
isoPath = isoVol.getPath();
|
isoPath = isoVol.getPath();
|
||||||
|
|
||||||
final DiskDef iso = new DiskDef();
|
iso.defISODisk(isoPath, diskSeq);
|
||||||
iso.defISODisk(isoPath);
|
|
||||||
isoXml = iso.toString();
|
|
||||||
} else {
|
} else {
|
||||||
final DiskDef iso = new DiskDef();
|
iso.defISODisk(null, diskSeq);
|
||||||
iso.defISODisk(null);
|
|
||||||
isoXml = iso.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DiskDef> disks = getDisks(conn, vmName);
|
final String result = attachOrDetachDevice(conn, true, vmName, iso.toString());
|
||||||
final String result = attachOrDetachDevice(conn, true, vmName, isoXml);
|
|
||||||
if (result == null && !isAttach) {
|
if (result == null && !isAttach) {
|
||||||
|
final List<DiskDef> disks = getDisks(conn, vmName);
|
||||||
for (final DiskDef disk : disks) {
|
for (final DiskDef disk : disks) {
|
||||||
if (disk.getDeviceType() == DiskDef.DeviceType.CDROM) {
|
if (disk.getDeviceType() == DiskDef.DeviceType.CDROM
|
||||||
|
&& (diskSeq == null || disk.getDiskLabel() == iso.getDiskLabel())) {
|
||||||
cleanupDisk(disk);
|
cleanupDisk(disk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import java.io.StringReader;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
@ -116,7 +115,7 @@ public class LibvirtDomainXMLParser {
|
|||||||
}
|
}
|
||||||
def.defFileBasedDisk(diskFile, diskLabel, DiskDef.DiskBus.valueOf(bus.toUpperCase()), fmt);
|
def.defFileBasedDisk(diskFile, diskLabel, DiskDef.DiskBus.valueOf(bus.toUpperCase()), fmt);
|
||||||
} else if (device.equalsIgnoreCase("cdrom")) {
|
} else if (device.equalsIgnoreCase("cdrom")) {
|
||||||
def.defISODisk(diskFile);
|
def.defISODisk(diskFile , i+1);
|
||||||
}
|
}
|
||||||
} else if (type.equalsIgnoreCase("block")) {
|
} else if (type.equalsIgnoreCase("block")) {
|
||||||
def.defBlockBasedDisk(diskDev, diskLabel,
|
def.defBlockBasedDisk(diskDev, diskLabel,
|
||||||
|
|||||||
@ -609,22 +609,24 @@ public class LibvirtVMDef {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip iso label */
|
/* skip iso labels */
|
||||||
private String getDevLabel(int devId, DiskBus bus) {
|
private String getDevLabel(int devId, DiskBus bus, boolean forIso) {
|
||||||
if (devId < 0) {
|
if (devId < 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (devId == 2) {
|
|
||||||
devId++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bus == DiskBus.SCSI) {
|
if (bus == DiskBus.SCSI) {
|
||||||
return "sd" + getDevLabelSuffix(devId);
|
return "sd" + getDevLabelSuffix(devId);
|
||||||
} else if (bus == DiskBus.VIRTIO) {
|
} else if (bus == DiskBus.VIRTIO) {
|
||||||
return "vd" + getDevLabelSuffix(devId);
|
return "vd" + getDevLabelSuffix(devId);
|
||||||
}
|
}
|
||||||
|
if (forIso) {
|
||||||
|
devId --;
|
||||||
|
} else if(devId >= 2) {
|
||||||
|
devId += 2;
|
||||||
|
}
|
||||||
return "hd" + getDevLabelSuffix(devId);
|
return "hd" + getDevLabelSuffix(devId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDevLabelSuffix(int deviceIndex) {
|
private String getDevLabelSuffix(int deviceIndex) {
|
||||||
@ -649,7 +651,7 @@ public class LibvirtVMDef {
|
|||||||
_deviceType = DeviceType.DISK;
|
_deviceType = DeviceType.DISK;
|
||||||
_diskCacheMode = DiskCacheMode.NONE;
|
_diskCacheMode = DiskCacheMode.NONE;
|
||||||
_sourcePath = filePath;
|
_sourcePath = filePath;
|
||||||
_diskLabel = getDevLabel(devId, bus);
|
_diskLabel = getDevLabel(devId, bus, false);
|
||||||
_diskFmtType = diskFmtType;
|
_diskFmtType = diskFmtType;
|
||||||
_bus = bus;
|
_bus = bus;
|
||||||
|
|
||||||
@ -659,19 +661,33 @@ public class LibvirtVMDef {
|
|||||||
_diskType = DiskType.FILE;
|
_diskType = DiskType.FILE;
|
||||||
_deviceType = DeviceType.CDROM;
|
_deviceType = DeviceType.CDROM;
|
||||||
_sourcePath = volPath;
|
_sourcePath = volPath;
|
||||||
_diskLabel = "hdc";
|
_diskLabel = getDevLabel(3, DiskBus.IDE, true);
|
||||||
_diskFmtType = DiskFmtType.RAW;
|
_diskFmtType = DiskFmtType.RAW;
|
||||||
_diskCacheMode = DiskCacheMode.NONE;
|
_diskCacheMode = DiskCacheMode.NONE;
|
||||||
_bus = DiskBus.IDE;
|
_bus = DiskBus.IDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void defISODisk(String volPath, Integer devId) {
|
||||||
|
if (devId == null) {
|
||||||
|
defISODisk(volPath);
|
||||||
|
} else {
|
||||||
|
_diskType = DiskType.FILE;
|
||||||
|
_deviceType = DeviceType.CDROM;
|
||||||
|
_sourcePath = volPath;
|
||||||
|
_diskLabel = getDevLabel(devId, DiskBus.IDE, true);
|
||||||
|
_diskFmtType = DiskFmtType.RAW;
|
||||||
|
_diskCacheMode = DiskCacheMode.NONE;
|
||||||
|
_bus = DiskBus.IDE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void defBlockBasedDisk(String diskName, int devId, DiskBus bus) {
|
public void defBlockBasedDisk(String diskName, int devId, DiskBus bus) {
|
||||||
_diskType = DiskType.BLOCK;
|
_diskType = DiskType.BLOCK;
|
||||||
_deviceType = DeviceType.DISK;
|
_deviceType = DeviceType.DISK;
|
||||||
_diskFmtType = DiskFmtType.RAW;
|
_diskFmtType = DiskFmtType.RAW;
|
||||||
_diskCacheMode = DiskCacheMode.NONE;
|
_diskCacheMode = DiskCacheMode.NONE;
|
||||||
_sourcePath = diskName;
|
_sourcePath = diskName;
|
||||||
_diskLabel = getDevLabel(devId, bus);
|
_diskLabel = getDevLabel(devId, bus, false);
|
||||||
_bus = bus;
|
_bus = bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,7 +712,7 @@ public class LibvirtVMDef {
|
|||||||
_sourcePort = sourcePort;
|
_sourcePort = sourcePort;
|
||||||
_authUserName = authUserName;
|
_authUserName = authUserName;
|
||||||
_authSecretUUID = authSecretUUID;
|
_authSecretUUID = authSecretUUID;
|
||||||
_diskLabel = getDevLabel(devId, bus);
|
_diskLabel = getDevLabel(devId, bus, false);
|
||||||
_bus = bus;
|
_bus = bus;
|
||||||
_diskProtocol = protocol;
|
_diskProtocol = protocol;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import java.net.URISyntaxException;
|
|||||||
import org.libvirt.Connect;
|
import org.libvirt.Connect;
|
||||||
import org.libvirt.LibvirtException;
|
import org.libvirt.LibvirtException;
|
||||||
|
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.AttachIsoAnswer;
|
||||||
import com.cloud.agent.api.AttachIsoCommand;
|
import com.cloud.agent.api.AttachIsoCommand;
|
||||||
import com.cloud.exception.InternalErrorException;
|
import com.cloud.exception.InternalErrorException;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||||
@ -32,23 +32,19 @@ import com.cloud.resource.CommandWrapper;
|
|||||||
import com.cloud.resource.ResourceWrapper;
|
import com.cloud.resource.ResourceWrapper;
|
||||||
|
|
||||||
@ResourceWrapper(handles = AttachIsoCommand.class)
|
@ResourceWrapper(handles = AttachIsoCommand.class)
|
||||||
public final class LibvirtAttachIsoCommandWrapper extends CommandWrapper<AttachIsoCommand, Answer, LibvirtComputingResource> {
|
public final class LibvirtAttachIsoCommandWrapper extends CommandWrapper<AttachIsoCommand, AttachIsoAnswer, LibvirtComputingResource> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Answer execute(final AttachIsoCommand command, final LibvirtComputingResource libvirtComputingResource) {
|
public AttachIsoAnswer execute(final AttachIsoCommand command, final LibvirtComputingResource libvirtComputingResource) {
|
||||||
try {
|
try {
|
||||||
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
|
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
|
||||||
|
|
||||||
final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(command.getVmName());
|
final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(command.getVmName());
|
||||||
libvirtComputingResource.attachOrDetachISO(conn, command.getVmName(), command.getIsoPath(), command.isAttach());
|
libvirtComputingResource.attachOrDetachISO(conn, command.getVmName(), command.getIsoPath(), command.isAttach(), command.getDeviceKey());
|
||||||
} catch (final LibvirtException e) {
|
} catch (final LibvirtException|URISyntaxException|InternalErrorException e) {
|
||||||
return new Answer(command, false, e.toString());
|
return new AttachIsoAnswer(command, e);
|
||||||
} catch (final URISyntaxException e) {
|
|
||||||
return new Answer(command, false, e.toString());
|
|
||||||
} catch (final InternalErrorException e) {
|
|
||||||
return new Answer(command, false, e.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Answer(command);
|
return new AttachIsoAnswer(command, command.getDeviceKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,7 +27,6 @@ import java.nio.channels.SocketChannel;
|
|||||||
import java.rmi.RemoteException;
|
import java.rmi.RemoteException;
|
||||||
|
|
||||||
import com.cloud.configuration.Resource.ResourceType;
|
import com.cloud.configuration.Resource.ResourceType;
|
||||||
import org.joda.time.Duration;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -43,13 +42,13 @@ import java.util.Random;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.math.NumberUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.apache.log4j.NDC;
|
import org.apache.log4j.NDC;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.joda.time.Duration;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.vmware.vim25.AboutInfo;
|
import com.vmware.vim25.AboutInfo;
|
||||||
import com.vmware.vim25.BoolPolicy;
|
import com.vmware.vim25.BoolPolicy;
|
||||||
@ -85,7 +84,6 @@ import com.vmware.vim25.VirtualDevice;
|
|||||||
import com.vmware.vim25.VirtualDeviceBackingInfo;
|
import com.vmware.vim25.VirtualDeviceBackingInfo;
|
||||||
import com.vmware.vim25.VirtualDeviceConfigSpec;
|
import com.vmware.vim25.VirtualDeviceConfigSpec;
|
||||||
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
|
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
|
||||||
import com.vmware.vim25.VirtualUSBController;
|
|
||||||
import com.vmware.vim25.VirtualDisk;
|
import com.vmware.vim25.VirtualDisk;
|
||||||
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
|
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
|
||||||
import com.vmware.vim25.VirtualEthernetCard;
|
import com.vmware.vim25.VirtualEthernetCard;
|
||||||
@ -102,6 +100,7 @@ import com.vmware.vim25.VirtualMachineRelocateSpec;
|
|||||||
import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator;
|
import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator;
|
||||||
import com.vmware.vim25.VirtualMachineRuntimeInfo;
|
import com.vmware.vim25.VirtualMachineRuntimeInfo;
|
||||||
import com.vmware.vim25.VirtualMachineVideoCard;
|
import com.vmware.vim25.VirtualMachineVideoCard;
|
||||||
|
import com.vmware.vim25.VirtualUSBController;
|
||||||
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
|
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
@ -111,10 +110,10 @@ import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource;
|
|||||||
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
import org.apache.commons.lang.math.NumberUtils;
|
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
||||||
|
|
||||||
import com.cloud.agent.IAgentControl;
|
import com.cloud.agent.IAgentControl;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.AttachIsoAnswer;
|
||||||
import com.cloud.agent.api.AttachIsoCommand;
|
import com.cloud.agent.api.AttachIsoCommand;
|
||||||
import com.cloud.agent.api.BackupSnapshotAnswer;
|
import com.cloud.agent.api.BackupSnapshotAnswer;
|
||||||
import com.cloud.agent.api.BackupSnapshotCommand;
|
import com.cloud.agent.api.BackupSnapshotCommand;
|
||||||
@ -259,7 +258,6 @@ import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
|
|||||||
import com.cloud.hypervisor.vmware.mo.NetworkDetails;
|
import com.cloud.hypervisor.vmware.mo.NetworkDetails;
|
||||||
import com.cloud.hypervisor.vmware.mo.TaskMO;
|
import com.cloud.hypervisor.vmware.mo.TaskMO;
|
||||||
import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType;
|
import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType;
|
||||||
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
|
||||||
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder;
|
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder;
|
||||||
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
||||||
import com.cloud.hypervisor.vmware.mo.VirtualSwitchType;
|
import com.cloud.hypervisor.vmware.mo.VirtualSwitchType;
|
||||||
@ -282,8 +280,8 @@ import com.cloud.storage.resource.StoragePoolResource;
|
|||||||
import com.cloud.storage.resource.StorageSubsystemCommandHandler;
|
import com.cloud.storage.resource.StorageSubsystemCommandHandler;
|
||||||
import com.cloud.storage.resource.VmwareStorageLayoutHelper;
|
import com.cloud.storage.resource.VmwareStorageLayoutHelper;
|
||||||
import com.cloud.storage.resource.VmwareStorageProcessor;
|
import com.cloud.storage.resource.VmwareStorageProcessor;
|
||||||
import com.cloud.storage.resource.VmwareStorageSubsystemCommandHandler;
|
|
||||||
import com.cloud.storage.resource.VmwareStorageProcessor.VmwareStorageProcessorConfigurableFields;
|
import com.cloud.storage.resource.VmwareStorageProcessor.VmwareStorageProcessorConfigurableFields;
|
||||||
|
import com.cloud.storage.resource.VmwareStorageSubsystemCommandHandler;
|
||||||
import com.cloud.storage.template.TemplateProp;
|
import com.cloud.storage.template.TemplateProp;
|
||||||
import com.cloud.utils.DateUtil;
|
import com.cloud.utils.DateUtil;
|
||||||
import com.cloud.utils.ExecutionResult;
|
import com.cloud.utils.ExecutionResult;
|
||||||
@ -1493,7 +1491,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Collections.sort(validatedDisks, (d1, d2) -> d1.getDiskSeq().compareTo(d2.getDiskSeq()));
|
||||||
return validatedDisks.toArray(new DiskTO[0]);
|
return validatedDisks.toArray(new DiskTO[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1880,10 +1878,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
|
s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
|
||||||
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
} else {
|
} else {
|
||||||
// Note: we will always plug a CDROM device
|
// Note: we will always plug a CDROM device
|
||||||
if (volIso != null) {
|
if (volIso != null) {
|
||||||
TemplateObjectTO iso = (TemplateObjectTO)volIso.getData();
|
for (DiskTO vol : disks) {
|
||||||
|
if (vol.getType() == Volume.Type.ISO) {
|
||||||
|
|
||||||
|
TemplateObjectTO iso = (TemplateObjectTO) vol.getData();
|
||||||
|
|
||||||
if (iso.getPath() != null && !iso.getPath().isEmpty()) {
|
if (iso.getPath() != null && !iso.getPath().isEmpty()) {
|
||||||
DataStoreTO imageStore = iso.getDataStore();
|
DataStoreTO imageStore = iso.getDataStore();
|
||||||
@ -1898,8 +1900,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
assert (isoDatastoreInfo.second() != null);
|
assert (isoDatastoreInfo.second() != null);
|
||||||
|
|
||||||
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
|
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
|
||||||
Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, ideUnitNumber++,
|
Pair<VirtualDevice, Boolean> isoInfo =
|
||||||
i + 1);
|
VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, ideUnitNumber++, i + 1);
|
||||||
deviceConfigSpecArray[i].setDevice(isoInfo.first());
|
deviceConfigSpecArray[i].setDevice(isoInfo.first());
|
||||||
if (isoInfo.second()) {
|
if (isoInfo.second()) {
|
||||||
if (s_logger.isDebugEnabled())
|
if (s_logger.isDebugEnabled())
|
||||||
@ -1911,6 +1913,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
|
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
|
||||||
Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, ideUnitNumber++, i + 1);
|
Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, ideUnitNumber++, i + 1);
|
||||||
@ -1926,10 +1931,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
|
|
||||||
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Setup ROOT/DATA disk devices
|
// Setup ROOT/DATA disk devices
|
||||||
@ -2910,10 +2916,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
|
|
||||||
private static VolumeObjectTO getVolumeInSpec(VirtualMachineTO vmSpec, VolumeObjectTO srcVol) {
|
private static VolumeObjectTO getVolumeInSpec(VirtualMachineTO vmSpec, VolumeObjectTO srcVol) {
|
||||||
for (DiskTO disk : vmSpec.getDisks()) {
|
for (DiskTO disk : vmSpec.getDisks()) {
|
||||||
|
if (disk.getData() instanceof VolumeObjectTO) {
|
||||||
VolumeObjectTO vol = (VolumeObjectTO) disk.getData();
|
VolumeObjectTO vol = (VolumeObjectTO) disk.getData();
|
||||||
if (vol.getId() == srcVol.getId())
|
if (vol.getId() == srcVol.getId())
|
||||||
return vol;
|
return vol;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -3237,6 +3245,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
String isoFileName = isoUrl.substring(isoFileNameStartPos);
|
String isoFileName = isoUrl.substring(isoFileNameStartPos);
|
||||||
|
|
||||||
int templateRootPos = isoUrl.indexOf("template/tmpl");
|
int templateRootPos = isoUrl.indexOf("template/tmpl");
|
||||||
|
templateRootPos = (templateRootPos < 0 ? isoUrl.indexOf("ConfigDrive") : templateRootPos);
|
||||||
if (templateRootPos < 0 ) {
|
if (templateRootPos < 0 ) {
|
||||||
throw new Exception("Invalid ISO path info");
|
throw new Exception("Invalid ISO path info");
|
||||||
}
|
}
|
||||||
@ -4195,7 +4204,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
return str.replace('/', '-');
|
return str.replace('/', '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Answer execute(AttachIsoCommand cmd) {
|
protected AttachIsoAnswer execute(AttachIsoCommand cmd) {
|
||||||
if (s_logger.isInfoEnabled()) {
|
if (s_logger.isInfoEnabled()) {
|
||||||
s_logger.info("Executing resource AttachIsoCommand: " + _gson.toJson(cmd));
|
s_logger.info("Executing resource AttachIsoCommand: " + _gson.toJson(cmd));
|
||||||
}
|
}
|
||||||
@ -4221,7 +4230,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
if (!vmMo.unmountToolsInstaller()) {
|
if (!vmMo.unmountToolsInstaller()) {
|
||||||
return new Answer(cmd, false,
|
return new AttachIsoAnswer(cmd, false,
|
||||||
"Failed to unmount vmware-tools installer ISO as the corresponding CDROM device is locked by VM. Please unmount the CDROM device inside the VM and ret-try.");
|
"Failed to unmount vmware-tools installer ISO as the corresponding CDROM device is locked by VM. Please unmount the CDROM device inside the VM and ret-try.");
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@ -4229,7 +4238,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Answer(cmd);
|
return new AttachIsoAnswer(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4244,7 +4253,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
|
|
||||||
int isoNameStartPos = isoPath.lastIndexOf('/');
|
int isoNameStartPos = isoPath.lastIndexOf('/');
|
||||||
String isoFileName = isoPath.substring(isoNameStartPos + 1);
|
String isoFileName = isoPath.substring(isoNameStartPos + 1);
|
||||||
String isoStorePathFromRoot = isoPath.substring(storeUrl.length(), isoNameStartPos);
|
String isoStorePathFromRoot = isoPath.substring(storeUrl.length() + 1, isoNameStartPos + 1);
|
||||||
|
|
||||||
|
|
||||||
// TODO, check if iso is already attached, or if there is a previous
|
// TODO, check if iso is already attached, or if there is a previous
|
||||||
// attachment
|
// attachment
|
||||||
@ -4253,12 +4263,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
String isoDatastorePath = String.format("[%s] %s%s", storeName, isoStorePathFromRoot, isoFileName);
|
String isoDatastorePath = String.format("[%s] %s%s", storeName, isoStorePathFromRoot, isoFileName);
|
||||||
|
|
||||||
if (cmd.isAttach()) {
|
if (cmd.isAttach()) {
|
||||||
vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false);
|
vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false, cmd.getDeviceKey());
|
||||||
|
return new AttachIsoAnswer(cmd);
|
||||||
} else {
|
} else {
|
||||||
vmMo.detachIso(isoDatastorePath);
|
int key = vmMo.detachIso(isoDatastorePath, cmd.isForce());
|
||||||
|
return new AttachIsoAnswer(cmd, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Answer(cmd);
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if (e instanceof RemoteException) {
|
if (e instanceof RemoteException) {
|
||||||
s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
|
s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
|
||||||
@ -4268,11 +4279,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
if (cmd.isAttach()) {
|
if (cmd.isAttach()) {
|
||||||
String msg = "AttachIsoCommand(attach) failed due to " + VmwareHelper.getExceptionMessage(e);
|
String msg = "AttachIsoCommand(attach) failed due to " + VmwareHelper.getExceptionMessage(e);
|
||||||
s_logger.error(msg, e);
|
s_logger.error(msg, e);
|
||||||
return new Answer(cmd, false, msg);
|
return new AttachIsoAnswer(cmd, false, msg);
|
||||||
} else {
|
} else {
|
||||||
String msg = "AttachIsoCommand(detach) failed due to " + VmwareHelper.getExceptionMessage(e);
|
String msg = "AttachIsoCommand(detach) failed due to " + VmwareHelper.getExceptionMessage(e);
|
||||||
s_logger.warn(msg, e);
|
s_logger.warn(msg, e);
|
||||||
return new Answer(cmd, false, msg);
|
return new AttachIsoAnswer(cmd, false, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,11 +33,11 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand;
|
import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.vmware.vim25.HostHostBusAdapter;
|
import com.vmware.vim25.HostHostBusAdapter;
|
||||||
import com.vmware.vim25.HostInternetScsiHba;
|
import com.vmware.vim25.HostInternetScsiHba;
|
||||||
@ -71,6 +71,7 @@ import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
|||||||
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
||||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
|
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
||||||
|
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
@ -93,7 +94,6 @@ import com.cloud.hypervisor.vmware.mo.HostMO;
|
|||||||
import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
|
import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
|
||||||
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
|
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
|
||||||
import com.cloud.hypervisor.vmware.mo.NetworkDetails;
|
import com.cloud.hypervisor.vmware.mo.NetworkDetails;
|
||||||
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
|
||||||
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
||||||
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
|
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
|
||||||
import com.cloud.hypervisor.vmware.resource.VmwareResource;
|
import com.cloud.hypervisor.vmware.resource.VmwareResource;
|
||||||
@ -1525,7 +1525,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
|
|
||||||
int isoNameStartPos = isoPath.lastIndexOf('/');
|
int isoNameStartPos = isoPath.lastIndexOf('/');
|
||||||
String isoFileName = isoPath.substring(isoNameStartPos + 1);
|
String isoFileName = isoPath.substring(isoNameStartPos + 1);
|
||||||
String isoStorePathFromRoot = isoPath.substring(storeUrl.length(), isoNameStartPos);
|
String isoStorePathFromRoot = isoPath.substring(storeUrl.length() + 1, isoNameStartPos);
|
||||||
|
|
||||||
// TODO, check if iso is already attached, or if there is a previous
|
// TODO, check if iso is already attached, or if there is a previous
|
||||||
// attachment
|
// attachment
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public final class CitrixPrepareForMigrationCommandWrapper extends CommandWrappe
|
|||||||
String configDriveLabel = vm.getConfigDriveLabel();
|
String configDriveLabel = vm.getConfigDriveLabel();
|
||||||
|
|
||||||
if (configDriveLabel == null) {
|
if (configDriveLabel == null) {
|
||||||
configDriveLabel = "config";
|
configDriveLabel = "config-2";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
|
|||||||
@ -19,7 +19,39 @@
|
|||||||
|
|
||||||
package com.cloud.network.element;
|
package com.cloud.network.element;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import net.nuage.vsp.acs.client.api.model.VspAclRule;
|
||||||
|
import net.nuage.vsp.acs.client.api.model.VspDhcpDomainOption;
|
||||||
|
import net.nuage.vsp.acs.client.api.model.VspNetwork;
|
||||||
|
import net.nuage.vsp.acs.client.api.model.VspStaticNat;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.InternalIdentity;
|
||||||
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
|
import org.apache.cloudstack.network.ExternalNetworkDeviceManager;
|
||||||
|
import org.apache.cloudstack.resourcedetail.VpcDetailVO;
|
||||||
|
import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao;
|
||||||
|
|
||||||
import com.cloud.agent.AgentManager;
|
import com.cloud.agent.AgentManager;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.agent.api.StartupCommand;
|
import com.cloud.agent.api.StartupCommand;
|
||||||
@ -56,7 +88,9 @@ import com.cloud.network.dao.FirewallRulesCidrsDao;
|
|||||||
import com.cloud.network.dao.FirewallRulesDao;
|
import com.cloud.network.dao.FirewallRulesDao;
|
||||||
import com.cloud.network.dao.IPAddressDao;
|
import com.cloud.network.dao.IPAddressDao;
|
||||||
import com.cloud.network.dao.IPAddressVO;
|
import com.cloud.network.dao.IPAddressVO;
|
||||||
|
import com.cloud.network.dao.NetworkDao;
|
||||||
import com.cloud.network.dao.NetworkServiceMapDao;
|
import com.cloud.network.dao.NetworkServiceMapDao;
|
||||||
|
import com.cloud.network.dao.NetworkVO;
|
||||||
import com.cloud.network.dao.PhysicalNetworkDao;
|
import com.cloud.network.dao.PhysicalNetworkDao;
|
||||||
import com.cloud.network.dao.PhysicalNetworkVO;
|
import com.cloud.network.dao.PhysicalNetworkVO;
|
||||||
import com.cloud.network.manager.NuageVspManager;
|
import com.cloud.network.manager.NuageVspManager;
|
||||||
@ -95,33 +129,6 @@ import com.cloud.vm.ReservationContext;
|
|||||||
import com.cloud.vm.VirtualMachineProfile;
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
import com.cloud.vm.dao.DomainRouterDao;
|
import com.cloud.vm.dao.DomainRouterDao;
|
||||||
import com.cloud.vm.dao.NicDao;
|
import com.cloud.vm.dao.NicDao;
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import net.nuage.vsp.acs.client.api.model.VspAclRule;
|
|
||||||
import net.nuage.vsp.acs.client.api.model.VspDhcpDomainOption;
|
|
||||||
import net.nuage.vsp.acs.client.api.model.VspNetwork;
|
|
||||||
import net.nuage.vsp.acs.client.api.model.VspStaticNat;
|
|
||||||
import org.apache.cloudstack.api.InternalIdentity;
|
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
|
||||||
import org.apache.cloudstack.network.ExternalNetworkDeviceManager;
|
|
||||||
import org.apache.cloudstack.resourcedetail.VpcDetailVO;
|
|
||||||
import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.naming.ConfigurationException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class NuageVspElement extends AdapterBase implements ConnectivityProvider, IpDeployer, SourceNatServiceProvider, StaticNatServiceProvider, FirewallServiceProvider,
|
public class NuageVspElement extends AdapterBase implements ConnectivityProvider, IpDeployer, SourceNatServiceProvider, StaticNatServiceProvider, FirewallServiceProvider,
|
||||||
DhcpServiceProvider, ResourceStateAdapter, VpcProvider, NetworkACLServiceProvider {
|
DhcpServiceProvider, ResourceStateAdapter, VpcProvider, NetworkACLServiceProvider {
|
||||||
@ -159,6 +166,8 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
|
|||||||
@Inject
|
@Inject
|
||||||
NetworkServiceMapDao _ntwkSrvcDao;
|
NetworkServiceMapDao _ntwkSrvcDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
NetworkDao _networkDao;
|
||||||
|
@Inject
|
||||||
DomainDao _domainDao;
|
DomainDao _domainDao;
|
||||||
@Inject
|
@Inject
|
||||||
IPAddressDao _ipAddressDao;
|
IPAddressDao _ipAddressDao;
|
||||||
@ -267,6 +276,13 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_nuageVspEntityBuilder.usesVirtualRouter(offering.getId())) {
|
||||||
|
// Update broadcast uri if VR is no longer used
|
||||||
|
NetworkVO networkToUpdate = _networkDao.findById(network.getId());
|
||||||
|
String broadcastUriStr = networkToUpdate.getUuid() + "/null";
|
||||||
|
networkToUpdate.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
|
||||||
|
_networkDao.update(network.getId(), networkToUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network);
|
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network);
|
||||||
List<VspAclRule> ingressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Ingress);
|
List<VspAclRule> ingressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Ingress);
|
||||||
@ -547,10 +563,11 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
|
|||||||
List<VlanVO> vlans = _vlanDao.listByZone(newVlan.getDataCenterId());
|
List<VlanVO> vlans = _vlanDao.listByZone(newVlan.getDataCenterId());
|
||||||
if (CollectionUtils.isNotEmpty(vlans)) {
|
if (CollectionUtils.isNotEmpty(vlans)) {
|
||||||
boolean newVlanUnderlay = NuageVspUtil.isUnderlayEnabledForVlan(_vlanDetailsDao, newVlan);
|
boolean newVlanUnderlay = NuageVspUtil.isUnderlayEnabledForVlan(_vlanDetailsDao, newVlan);
|
||||||
|
final String newCidr = NetUtils.getCidrFromGatewayAndNetmask(newVlan.getVlanGateway(), newVlan.getVlanNetmask());
|
||||||
|
|
||||||
for (VlanVO vlan : vlans) {
|
for (VlanVO vlan : vlans) {
|
||||||
if (vlan.getId() == newVlan.getId()) continue;
|
if (vlan.getId() == newVlan.getId()) continue;
|
||||||
|
|
||||||
final String newCidr = NetUtils.getCidrFromGatewayAndNetmask(newVlan.getVlanGateway(), newVlan.getVlanNetmask());
|
|
||||||
final String existingCidr = NetUtils.getCidrFromGatewayAndNetmask(vlan.getVlanGateway(), vlan.getVlanNetmask());
|
final String existingCidr = NetUtils.getCidrFromGatewayAndNetmask(vlan.getVlanGateway(), vlan.getVlanNetmask());
|
||||||
|
|
||||||
NetUtils.SupersetOrSubset supersetOrSubset = NetUtils.isNetowrkASubsetOrSupersetOfNetworkB(newCidr, existingCidr);
|
NetUtils.SupersetOrSubset supersetOrSubset = NetUtils.isNetowrkASubsetOrSupersetOfNetworkB(newCidr, existingCidr);
|
||||||
@ -635,7 +652,7 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
|
|||||||
@Override
|
@Override
|
||||||
public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
|
||||||
List<VpcOfferingServiceMapVO> vpcOfferingServices = _vpcOfferingSrvcDao.listByVpcOffId(vpc.getVpcOfferingId());
|
List<VpcOfferingServiceMapVO> vpcOfferingServices = _vpcOfferingSrvcDao.listByVpcOffId(vpc.getVpcOfferingId());
|
||||||
Multimap<Service, Provider> supportedVpcServices = NuageVspManagerImpl.NUAGE_VSP_VPC_SERVICE_MAP;
|
Multimap<Service, Provider> supportedVpcServices = NuageVspManagerImpl.SUPPORTED_NUAGE_VSP_VPC_SERVICE_MAP;
|
||||||
for (VpcOfferingServiceMapVO vpcOfferingService : vpcOfferingServices) {
|
for (VpcOfferingServiceMapVO vpcOfferingService : vpcOfferingServices) {
|
||||||
Network.Service service = Network.Service.getService(vpcOfferingService.getService());
|
Network.Service service = Network.Service.getService(vpcOfferingService.getService());
|
||||||
if (!supportedVpcServices.containsKey(service)) {
|
if (!supportedVpcServices.containsKey(service)) {
|
||||||
|
|||||||
@ -61,6 +61,7 @@ import com.cloud.dc.DataCenter.NetworkType;
|
|||||||
import com.cloud.dc.DataCenterDetailVO;
|
import com.cloud.dc.DataCenterDetailVO;
|
||||||
import com.cloud.dc.VlanVO;
|
import com.cloud.dc.VlanVO;
|
||||||
import com.cloud.dc.dao.DataCenterDetailsDao;
|
import com.cloud.dc.dao.DataCenterDetailsDao;
|
||||||
|
import com.cloud.dc.dao.VlanDetailsDao;
|
||||||
import com.cloud.deploy.DeployDestination;
|
import com.cloud.deploy.DeployDestination;
|
||||||
import com.cloud.deploy.DeploymentPlan;
|
import com.cloud.deploy.DeploymentPlan;
|
||||||
import com.cloud.domain.dao.DomainDao;
|
import com.cloud.domain.dao.DomainDao;
|
||||||
@ -88,6 +89,7 @@ import com.cloud.user.Account;
|
|||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
import com.cloud.util.NuageVspEntityBuilder;
|
import com.cloud.util.NuageVspEntityBuilder;
|
||||||
|
import com.cloud.util.NuageVspUtil;
|
||||||
import com.cloud.utils.StringUtils;
|
import com.cloud.utils.StringUtils;
|
||||||
import com.cloud.utils.db.DB;
|
import com.cloud.utils.db.DB;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
@ -130,6 +132,8 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||||||
NetworkOrchestrationService _networkOrchestrationService;
|
NetworkOrchestrationService _networkOrchestrationService;
|
||||||
@Inject
|
@Inject
|
||||||
DataCenterDetailsDao _dcDetailsDao;
|
DataCenterDetailsDao _dcDetailsDao;
|
||||||
|
@Inject
|
||||||
|
VlanDetailsDao _vlanDetailsDao;
|
||||||
|
|
||||||
public NuageVspGuestNetworkGuru() {
|
public NuageVspGuestNetworkGuru() {
|
||||||
super();
|
super();
|
||||||
@ -299,6 +303,24 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||||||
}
|
}
|
||||||
|
|
||||||
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented, true);
|
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented, true);
|
||||||
|
|
||||||
|
if (vspNetwork.isShared()) {
|
||||||
|
Boolean previousUnderlay= null;
|
||||||
|
for (VlanVO vlan : _vlanDao.listVlansByNetworkId(networkId)) {
|
||||||
|
boolean underlay = NuageVspUtil.isUnderlayEnabledForVlan(_vlanDetailsDao, vlan);
|
||||||
|
if (previousUnderlay == null || underlay == previousUnderlay) {
|
||||||
|
previousUnderlay = underlay;
|
||||||
|
} else {
|
||||||
|
throw new CloudRuntimeException("Mixed values for the underlay flag for IP ranges in the same subnet is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (previousUnderlay != null) {
|
||||||
|
vspNetwork = new VspNetwork.Builder().fromObject(vspNetwork)
|
||||||
|
.vlanUnderlay(previousUnderlay)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId();
|
String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId();
|
||||||
String broadcastUriStr = implemented.getUuid() + "/" + vspNetwork.getVirtualRouterIp();
|
String broadcastUriStr = implemented.getUuid() + "/" + vspNetwork.getVirtualRouterIp();
|
||||||
implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
|
implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
|
||||||
@ -495,6 +517,16 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||||||
//update the extra DHCP options
|
//update the extra DHCP options
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// Update broadcast Uri to enable VR ip update
|
||||||
|
if (!network.getBroadcastUri().getPath().substring(1).equals(vspNetwork.getVirtualRouterIp())) {
|
||||||
|
NetworkVO networkToUpdate = _networkDao.findById(network.getId());
|
||||||
|
String broadcastUriStr = networkToUpdate.getUuid() + "/" + vspNetwork.getVirtualRouterIp();
|
||||||
|
networkToUpdate.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
|
||||||
|
_networkDao.update(network.getId(), networkToUpdate);
|
||||||
|
if (network instanceof NetworkVO) {
|
||||||
|
((NetworkVO) network).setBroadcastUri(networkToUpdate.getBroadcastUri());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nic.setBroadcastUri(network.getBroadcastUri());
|
nic.setBroadcastUri(network.getBroadcastUri());
|
||||||
nic.setIsolationUri(network.getBroadcastUri());
|
nic.setIsolationUri(network.getBroadcastUri());
|
||||||
@ -586,8 +618,15 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean isServiceProvidedByVR(Network network, Network.Service service ) {
|
||||||
|
return (_networkModel.areServicesSupportedInNetwork(network.getId(), service) &&
|
||||||
|
( _networkModel.isProviderSupportServiceInNetwork(network.getId(), service, Network.Provider.VirtualRouter) ||
|
||||||
|
_networkModel.isProviderSupportServiceInNetwork(network.getId(), service, Network.Provider.VPCVirtualRouter)));
|
||||||
|
}
|
||||||
|
|
||||||
private void checkMultipleSubnetsCombinedWithUseData(Network network) {
|
private void checkMultipleSubnetsCombinedWithUseData(Network network) {
|
||||||
if (_ntwkOfferingSrvcDao.listServicesForNetworkOffering(network.getNetworkOfferingId()).contains(Network.Service.UserData.getName())) {
|
if (isServiceProvidedByVR(network, Network.Service.UserData)) {
|
||||||
List<VlanVO> vlanVOs = _vlanDao.listVlansByNetworkId(network.getId());
|
List<VlanVO> vlanVOs = _vlanDao.listVlansByNetworkId(network.getId());
|
||||||
if (vlanVOs.stream()
|
if (vlanVOs.stream()
|
||||||
.map(VlanVO::getVlanGateway)
|
.map(VlanVO::getVlanGateway)
|
||||||
|
|||||||
@ -161,7 +161,8 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
|
|||||||
|
|
||||||
private static final Logger s_logger = Logger.getLogger(NuageVspManagerImpl.class);
|
private static final Logger s_logger = Logger.getLogger(NuageVspManagerImpl.class);
|
||||||
|
|
||||||
public static final Multimap<Network.Service, Network.Provider> NUAGE_VSP_VPC_SERVICE_MAP;
|
public static final Multimap<Network.Service, Network.Provider> DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP;
|
||||||
|
public static final Multimap<Network.Service, Network.Provider> SUPPORTED_NUAGE_VSP_VPC_SERVICE_MAP;
|
||||||
private static final ConfigKey[] NUAGE_VSP_CONFIG_KEYS = new ConfigKey<?>[] { NuageVspConfigDns, NuageVspDnsExternal, NuageVspConfigGateway,
|
private static final ConfigKey[] NUAGE_VSP_CONFIG_KEYS = new ConfigKey<?>[] { NuageVspConfigDns, NuageVspDnsExternal, NuageVspConfigGateway,
|
||||||
NuageVspSharedNetworkDomainTemplateName, NuageVspVpcDomainTemplateName, NuageVspIsolatedNetworkDomainTemplateName };
|
NuageVspSharedNetworkDomainTemplateName, NuageVspVpcDomainTemplateName, NuageVspIsolatedNetworkDomainTemplateName };
|
||||||
|
|
||||||
@ -216,8 +217,11 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
|
|||||||
static {
|
static {
|
||||||
Set<Network.Provider> nuageVspProviders = ImmutableSet.of(Network.Provider.NuageVsp);
|
Set<Network.Provider> nuageVspProviders = ImmutableSet.of(Network.Provider.NuageVsp);
|
||||||
Set<Network.Provider> vrProviders = ImmutableSet.of(Network.Provider.VPCVirtualRouter);
|
Set<Network.Provider> vrProviders = ImmutableSet.of(Network.Provider.VPCVirtualRouter);
|
||||||
Set<Network.Provider> lbProviders = ImmutableSet.of(Network.Provider.InternalLbVm);
|
Set<Network.Provider> defaultLbProviders = ImmutableSet.of(Network.Provider.InternalLbVm);
|
||||||
NUAGE_VSP_VPC_SERVICE_MAP = ImmutableMultimap.<Network.Service, Network.Provider>builder()
|
Set<Network.Provider> supportedLbProviders = ImmutableSet.of(Network.Provider.InternalLbVm);
|
||||||
|
Set<Network.Provider> supportedUserDataProviders = ImmutableSet.of(Network.Provider.VPCVirtualRouter, Network.Provider.ConfigDrive);
|
||||||
|
|
||||||
|
DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP = ImmutableMultimap.<Network.Service, Network.Provider>builder()
|
||||||
.putAll(Network.Service.Connectivity, nuageVspProviders)
|
.putAll(Network.Service.Connectivity, nuageVspProviders)
|
||||||
.putAll(Network.Service.Gateway, nuageVspProviders)
|
.putAll(Network.Service.Gateway, nuageVspProviders)
|
||||||
.putAll(Network.Service.Dhcp, nuageVspProviders)
|
.putAll(Network.Service.Dhcp, nuageVspProviders)
|
||||||
@ -225,9 +229,15 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
|
|||||||
.putAll(Network.Service.SourceNat, nuageVspProviders)
|
.putAll(Network.Service.SourceNat, nuageVspProviders)
|
||||||
.putAll(Network.Service.NetworkACL, nuageVspProviders)
|
.putAll(Network.Service.NetworkACL, nuageVspProviders)
|
||||||
.putAll(Network.Service.UserData, vrProviders)
|
.putAll(Network.Service.UserData, vrProviders)
|
||||||
.putAll(Network.Service.Lb, lbProviders)
|
.putAll(Network.Service.Lb, defaultLbProviders)
|
||||||
.putAll(Network.Service.Dns, vrProviders)
|
.putAll(Network.Service.Dns, vrProviders)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
Multimap<Network.Service, Network.Provider> builder = HashMultimap.create(DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP);
|
||||||
|
builder.putAll(Network.Service.UserData, supportedUserDataProviders);
|
||||||
|
builder.putAll(Network.Service.Lb, supportedLbProviders);
|
||||||
|
|
||||||
|
SUPPORTED_NUAGE_VSP_VPC_SERVICE_MAP = ImmutableMultimap.copyOf(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Listener _nuageVspResourceListener;
|
private Listener _nuageVspResourceListener;
|
||||||
@ -1193,9 +1203,9 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
|
|||||||
s_logger.debug("Creating default Nuage VPC offering " + nuageVPCOfferingName);
|
s_logger.debug("Creating default Nuage VPC offering " + nuageVPCOfferingName);
|
||||||
}
|
}
|
||||||
|
|
||||||
createVpcOffering(nuageVPCOfferingName, nuageVPCOfferingDisplayText, NUAGE_VSP_VPC_SERVICE_MAP, true, VpcOffering.State.Enabled, null);
|
createVpcOffering(nuageVPCOfferingName, nuageVPCOfferingDisplayText, DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP, true, VpcOffering.State.Enabled, null);
|
||||||
} else {
|
} else {
|
||||||
updateVpcOffering(offering, NUAGE_VSP_VPC_SERVICE_MAP);
|
updateVpcOffering(offering, DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -22,9 +22,11 @@ package com.cloud.network.resource;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
|
||||||
import net.nuage.vsp.acs.client.api.NuageVspAclClient;
|
import net.nuage.vsp.acs.client.api.NuageVspAclClient;
|
||||||
import net.nuage.vsp.acs.client.api.NuageVspApiClient;
|
import net.nuage.vsp.acs.client.api.NuageVspApiClient;
|
||||||
import net.nuage.vsp.acs.client.api.NuageVspElementClient;
|
import net.nuage.vsp.acs.client.api.NuageVspElementClient;
|
||||||
@ -36,10 +38,6 @@ import net.nuage.vsp.acs.client.common.RequestType;
|
|||||||
import net.nuage.vsp.acs.client.common.model.NuageVspEntity;
|
import net.nuage.vsp.acs.client.common.model.NuageVspEntity;
|
||||||
import net.nuage.vsp.acs.client.exception.NuageVspException;
|
import net.nuage.vsp.acs.client.exception.NuageVspException;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
|
|
||||||
import com.cloud.agent.IAgentControl;
|
import com.cloud.agent.IAgentControl;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
|
|||||||
@ -227,7 +227,6 @@ public class NuageVspEntityBuilder {
|
|||||||
|
|
||||||
if (networkOffering.getGuestType() == Network.GuestType.Shared) {
|
if (networkOffering.getGuestType() == Network.GuestType.Shared) {
|
||||||
List<VlanVO> vlans = _vlanDao.listVlansByNetworkIdIncludingRemoved(network.getId());
|
List<VlanVO> vlans = _vlanDao.listVlansByNetworkIdIncludingRemoved(network.getId());
|
||||||
|
|
||||||
List<VspAddressRange> vspAddressRanges =
|
List<VspAddressRange> vspAddressRanges =
|
||||||
vlans.stream()
|
vlans.stream()
|
||||||
.map(vlan -> new VspAddressRange.Builder().gateway(vlan.getVlanGateway()).netmask(vlan.getVlanNetmask()).build())
|
.map(vlan -> new VspAddressRange.Builder().gateway(vlan.getVlanGateway()).netmask(vlan.getVlanNetmask()).build())
|
||||||
@ -290,9 +289,11 @@ public class NuageVspEntityBuilder {
|
|||||||
.findFirst()
|
.findFirst()
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
|
boolean underlayEnabled = NuageVspUtil.isUnderlayEnabledForVlan(_vlanDetailsDao, matchingVlan);
|
||||||
return new VspNetwork.Builder().fromObject(vspNetwork)
|
return new VspNetwork.Builder().fromObject(vspNetwork)
|
||||||
.gateway(matchingVlan.getVlanGateway())
|
.gateway(matchingVlan.getVlanGateway())
|
||||||
.cidr(NetUtils.getCidrFromGatewayAndNetmask(matchingVlan.getVlanGateway(), matchingVlan.getVlanNetmask()))
|
.cidr(NetUtils.getCidrFromGatewayAndNetmask(matchingVlan.getVlanGateway(), matchingVlan.getVlanNetmask()))
|
||||||
|
.vlanUnderlay(underlayEnabled)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,7 +60,9 @@ import com.cloud.network.NuageVspDeviceVO;
|
|||||||
import com.cloud.network.dao.FirewallRulesDao;
|
import com.cloud.network.dao.FirewallRulesDao;
|
||||||
import com.cloud.network.dao.IPAddressDao;
|
import com.cloud.network.dao.IPAddressDao;
|
||||||
import com.cloud.network.dao.IPAddressVO;
|
import com.cloud.network.dao.IPAddressVO;
|
||||||
|
import com.cloud.network.dao.NetworkDao;
|
||||||
import com.cloud.network.dao.NetworkServiceMapDao;
|
import com.cloud.network.dao.NetworkServiceMapDao;
|
||||||
|
import com.cloud.network.dao.NetworkVO;
|
||||||
import com.cloud.network.dao.NuageVspDao;
|
import com.cloud.network.dao.NuageVspDao;
|
||||||
import com.cloud.network.dao.PhysicalNetworkDao;
|
import com.cloud.network.dao.PhysicalNetworkDao;
|
||||||
import com.cloud.network.dao.PhysicalNetworkVO;
|
import com.cloud.network.dao.PhysicalNetworkVO;
|
||||||
@ -109,6 +111,7 @@ public class NuageVspElementTest extends NuageTest {
|
|||||||
@Mock private DomainRouterDao _domainRouterDao;
|
@Mock private DomainRouterDao _domainRouterDao;
|
||||||
@Mock private ResourceManager _resourceManager;
|
@Mock private ResourceManager _resourceManager;
|
||||||
@Mock private ResourceTagDao _resourceTagDao;
|
@Mock private ResourceTagDao _resourceTagDao;
|
||||||
|
@Mock private NetworkDao _networkDao;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@ -173,6 +176,11 @@ public class NuageVspElementTest extends NuageTest {
|
|||||||
when(network.getDataCenterId()).thenReturn(NETWORK_ID);
|
when(network.getDataCenterId()).thenReturn(NETWORK_ID);
|
||||||
when(_networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true);
|
when(_networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true);
|
||||||
|
|
||||||
|
final NetworkVO networkVO = mock(NetworkVO.class);
|
||||||
|
when(network.getUuid()).thenReturn("aaaaaa");
|
||||||
|
|
||||||
|
when(_networkDao.findById(NETWORK_ID)).thenReturn(networkVO);
|
||||||
|
|
||||||
final NetworkOffering offering = mock(NetworkOffering.class);
|
final NetworkOffering offering = mock(NetworkOffering.class);
|
||||||
when(offering.getId()).thenReturn(NETWORK_ID);
|
when(offering.getId()).thenReturn(NETWORK_ID);
|
||||||
when(offering.getTrafficType()).thenReturn(TrafficType.Guest);
|
when(offering.getTrafficType()).thenReturn(TrafficType.Guest);
|
||||||
|
|||||||
@ -335,6 +335,8 @@ public class NuageVspGuestNetworkGuruTest extends NuageTest {
|
|||||||
when(reservationContext.getAccount()).thenReturn(networksAccount);
|
when(reservationContext.getAccount()).thenReturn(networksAccount);
|
||||||
when(reservationContext.getDomain()).thenReturn(networksDomain);
|
when(reservationContext.getDomain()).thenReturn(networksDomain);
|
||||||
|
|
||||||
|
when(_networkDao.findById(NETWORK_ID)).thenReturn(network);
|
||||||
|
|
||||||
_nuageVspGuestNetworkGuru.reserve(nicProfile, network, vmProfile, mock(DeployDestination.class), reservationContext);
|
_nuageVspGuestNetworkGuru.reserve(nicProfile, network, vmProfile, mock(DeployDestination.class), reservationContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -96,8 +96,8 @@ public class NuageVspEntityBuilderTest extends NuageTest {
|
|||||||
@Mock private NetworkDetailsDao _networkDetailsDao;
|
@Mock private NetworkDetailsDao _networkDetailsDao;
|
||||||
@Mock private NetworkOfferingDao _networkOfferingDao;
|
@Mock private NetworkOfferingDao _networkOfferingDao;
|
||||||
@Mock private NetworkOfferingServiceMapDao _networkOfferingServiceMapDao;
|
@Mock private NetworkOfferingServiceMapDao _networkOfferingServiceMapDao;
|
||||||
@Mock private NicSecondaryIpDao _nicSecondaryIpDao;
|
|
||||||
@Mock private NicDao _nicDao;
|
@Mock private NicDao _nicDao;
|
||||||
|
@Mock private NicSecondaryIpDao _nicSecondaryIpDao;
|
||||||
@Mock private VlanDao _vlanDao;
|
@Mock private VlanDao _vlanDao;
|
||||||
@Mock private VlanDetailsDao _vlanDetailsDao;
|
@Mock private VlanDetailsDao _vlanDetailsDao;
|
||||||
@Mock private VpcDao _vpcDao;
|
@Mock private VpcDao _vpcDao;
|
||||||
|
|||||||
@ -61,4 +61,8 @@
|
|||||||
<property name="name" value="VirtualRouter" />
|
<property name="name" value="VirtualRouter" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="ConfigDrive" class="com.cloud.network.element.ConfigDriveNetworkElement">
|
||||||
|
<property name="name" value="ConfigDrive" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
|||||||
@ -30,20 +30,19 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
|
||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao;
|
import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao;
|
||||||
|
|
||||||
import com.cloud.api.ApiDBUtils;
|
import com.cloud.api.ApiDBUtils;
|
||||||
import com.cloud.configuration.Config;
|
import com.cloud.configuration.Config;
|
||||||
import com.cloud.configuration.ConfigurationManager;
|
import com.cloud.configuration.ConfigurationManager;
|
||||||
@ -2349,14 +2348,14 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
|||||||
final List<String[]> vmData = new ArrayList<String[]>();
|
final List<String[]> vmData = new ArrayList<String[]>();
|
||||||
|
|
||||||
if (userData != null) {
|
if (userData != null) {
|
||||||
vmData.add(new String[]{"userdata", "user-data", new String(Base64.decodeBase64(userData),StringUtils.getPreferredCharset())});
|
vmData.add(new String[]{USERDATA_DIR, USERDATA_FILE, new String(Base64.decodeBase64(userData),StringUtils.getPreferredCharset())});
|
||||||
}
|
}
|
||||||
vmData.add(new String[]{"metadata", "service-offering", StringUtils.unicodeEscape(serviceOffering)});
|
vmData.add(new String[]{METATDATA_DIR, SERVICE_OFFERING_FILE, StringUtils.unicodeEscape(serviceOffering)});
|
||||||
vmData.add(new String[]{"metadata", "availability-zone", StringUtils.unicodeEscape(zoneName)});
|
vmData.add(new String[]{METATDATA_DIR, AVAILABILITY_ZONE_FILE, StringUtils.unicodeEscape(zoneName)});
|
||||||
vmData.add(new String[]{"metadata", "local-hostname", StringUtils.unicodeEscape(vmName)});
|
vmData.add(new String[]{METATDATA_DIR, LOCAL_HOSTNAME_FILE, StringUtils.unicodeEscape(vmName)});
|
||||||
vmData.add(new String[]{"metadata", "instance-id", vmName});
|
vmData.add(new String[]{METATDATA_DIR, INSTANCE_ID_FILE, vmName});
|
||||||
vmData.add(new String[]{"metadata", "vm-id", String.valueOf(vmId)});
|
vmData.add(new String[]{METATDATA_DIR, VM_ID_FILE, String.valueOf(vmId)});
|
||||||
vmData.add(new String[]{"metadata", "public-keys", publicKey});
|
vmData.add(new String[]{METATDATA_DIR, PUBLIC_KEYS_FILE, publicKey});
|
||||||
|
|
||||||
String cloudIdentifier = _configDao.getValue("cloud.identifier");
|
String cloudIdentifier = _configDao.getValue("cloud.identifier");
|
||||||
if (cloudIdentifier == null) {
|
if (cloudIdentifier == null) {
|
||||||
@ -2364,7 +2363,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
|||||||
} else {
|
} else {
|
||||||
cloudIdentifier = "CloudStack-{" + cloudIdentifier + "}";
|
cloudIdentifier = "CloudStack-{" + cloudIdentifier + "}";
|
||||||
}
|
}
|
||||||
vmData.add(new String[]{"metadata", "cloud-identifier", cloudIdentifier});
|
vmData.add(new String[]{METATDATA_DIR, CLOUD_IDENTIFIER_FILE, cloudIdentifier});
|
||||||
|
|
||||||
if (password != null && !password.isEmpty() && !password.equals("saved_password")) {
|
if (password != null && !password.isEmpty() && !password.equals("saved_password")) {
|
||||||
|
|
||||||
@ -2385,10 +2384,10 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
|||||||
BigInteger bigInt = new BigInteger(1, digest);
|
BigInteger bigInt = new BigInteger(1, digest);
|
||||||
String hashtext = bigInt.toString(16);
|
String hashtext = bigInt.toString(16);
|
||||||
|
|
||||||
vmData.add(new String[]{"password", "vm-password-md5checksum", hashtext});
|
vmData.add(new String[]{PASSWORD_DIR, PASSWORD_CHECKSUM_FILE, hashtext});
|
||||||
}
|
}
|
||||||
|
|
||||||
vmData.add(new String[]{"password", "vm-password", password});
|
vmData.add(new String[]{PASSWORD_DIR, PASSWORD_FILE, password});
|
||||||
}
|
}
|
||||||
|
|
||||||
return vmData;
|
return vmData;
|
||||||
|
|||||||
@ -2896,6 +2896,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
|
|||||||
//Add Internal Load Balancer element as a default network service provider
|
//Add Internal Load Balancer element as a default network service provider
|
||||||
addDefaultInternalLbProviderToPhysicalNetwork(pNetwork.getId());
|
addDefaultInternalLbProviderToPhysicalNetwork(pNetwork.getId());
|
||||||
|
|
||||||
|
// Add the config drive provider
|
||||||
|
addConfigDriveToPhysicalNetwork(pNetwork.getId());
|
||||||
|
|
||||||
return pNetwork;
|
return pNetwork;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -4198,13 +4201,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
|
|||||||
addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalUserdataProvider", null, null);
|
addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalUserdataProvider", null, null);
|
||||||
} else if (dvo.getNetworkType() == NetworkType.Advanced) {
|
} else if (dvo.getNetworkType() == NetworkType.Advanced) {
|
||||||
addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalPxeProvider", null, null);
|
addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalPxeProvider", null, null);
|
||||||
enableBaremetalProvider("BaremetalPxeProvider");
|
enableProvider("BaremetalPxeProvider");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableBaremetalProvider(String providerName) {
|
private void enableProvider(String providerName) {
|
||||||
QueryBuilder<PhysicalNetworkServiceProviderVO> q = QueryBuilder.create(PhysicalNetworkServiceProviderVO.class);
|
QueryBuilder<PhysicalNetworkServiceProviderVO> q = QueryBuilder.create(PhysicalNetworkServiceProviderVO.class);
|
||||||
q.and(q.entity().getProviderName(), SearchCriteria.Op.EQ, providerName);
|
q.and(q.entity().getProviderName(), SearchCriteria.Op.EQ, providerName);
|
||||||
PhysicalNetworkServiceProviderVO provider = q.find();
|
PhysicalNetworkServiceProviderVO provider = q.find();
|
||||||
@ -4212,6 +4215,22 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
|
|||||||
_pNSPDao.update(provider.getId(), provider);
|
_pNSPDao.update(provider.getId(), provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PhysicalNetworkServiceProvider addConfigDriveToPhysicalNetwork(long physicalNetworkId) {
|
||||||
|
PhysicalNetworkVO pvo = _physicalNetworkDao.findById(physicalNetworkId);
|
||||||
|
DataCenterVO dvo = _dcDao.findById(pvo.getDataCenterId());
|
||||||
|
if (dvo.getNetworkType() == NetworkType.Advanced) {
|
||||||
|
|
||||||
|
Provider provider = Network.Provider.getProvider("ConfigDrive");
|
||||||
|
if (provider == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
addProviderToPhysicalNetwork(physicalNetworkId, Provider.ConfigDrive.getName(), null, null);
|
||||||
|
enableProvider(Provider.ConfigDrive.getName());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
protected boolean isNetworkSystem(Network network) {
|
protected boolean isNetworkSystem(Network network) {
|
||||||
NetworkOffering no = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
|
NetworkOffering no = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId());
|
||||||
if (no.isSystemOnly()) {
|
if (no.isSystemOnly()) {
|
||||||
|
|||||||
@ -0,0 +1,424 @@
|
|||||||
|
// 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.network.element;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
|
||||||
|
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||||
|
import com.cloud.agent.AgentManager;
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.AttachIsoAnswer;
|
||||||
|
import com.cloud.agent.api.AttachIsoCommand;
|
||||||
|
import com.cloud.agent.api.HandleConfigDriveIsoCommand;
|
||||||
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
|
import com.cloud.configuration.ConfigurationManager;
|
||||||
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
|
import com.cloud.deploy.DeployDestination;
|
||||||
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
|
import com.cloud.exception.OperationTimedoutException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.exception.UnsupportedServiceException;
|
||||||
|
import com.cloud.host.Host;
|
||||||
|
import com.cloud.host.dao.HostDao;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.Network.Capability;
|
||||||
|
import com.cloud.network.Network.Provider;
|
||||||
|
import com.cloud.network.Network.Service;
|
||||||
|
import com.cloud.network.NetworkMigrationResponder;
|
||||||
|
import com.cloud.network.NetworkModel;
|
||||||
|
import com.cloud.network.Networks.TrafficType;
|
||||||
|
import com.cloud.network.PhysicalNetworkServiceProvider;
|
||||||
|
import com.cloud.network.dao.NetworkDao;
|
||||||
|
import com.cloud.offering.NetworkOffering;
|
||||||
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
|
import com.cloud.storage.Volume;
|
||||||
|
import com.cloud.storage.dao.GuestOSCategoryDao;
|
||||||
|
import com.cloud.storage.dao.GuestOSDao;
|
||||||
|
import com.cloud.utils.component.AdapterBase;
|
||||||
|
import com.cloud.utils.fsm.StateListener;
|
||||||
|
import com.cloud.utils.fsm.StateMachine2;
|
||||||
|
import com.cloud.vm.Nic;
|
||||||
|
import com.cloud.vm.NicProfile;
|
||||||
|
import com.cloud.vm.ReservationContext;
|
||||||
|
import com.cloud.vm.UserVmDetailVO;
|
||||||
|
import com.cloud.vm.UserVmManager;
|
||||||
|
import com.cloud.vm.UserVmVO;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import com.cloud.vm.VirtualMachineManager;
|
||||||
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
|
import com.cloud.vm.dao.DomainRouterDao;
|
||||||
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
|
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||||
|
|
||||||
|
public class ConfigDriveNetworkElement extends AdapterBase implements NetworkElement, UserDataServiceProvider,
|
||||||
|
StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualMachine>, NetworkMigrationResponder {
|
||||||
|
private static final Logger s_logger = Logger.getLogger(ConfigDriveNetworkElement.class);
|
||||||
|
|
||||||
|
private static final Map<Service, Map<Capability, String>> capabilities = setCapabilities();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
NetworkDao _networkConfigDao;
|
||||||
|
@Inject
|
||||||
|
NetworkModel _networkMgr;
|
||||||
|
@Inject
|
||||||
|
UserVmManager _userVmMgr;
|
||||||
|
@Inject
|
||||||
|
UserVmDao _userVmDao;
|
||||||
|
@Inject
|
||||||
|
UserVmDetailsDao _userVmDetailsDao;
|
||||||
|
@Inject
|
||||||
|
DomainRouterDao _routerDao;
|
||||||
|
@Inject
|
||||||
|
ConfigurationManager _configMgr;
|
||||||
|
@Inject
|
||||||
|
DataCenterDao _dcDao;
|
||||||
|
@Inject
|
||||||
|
AgentManager _agentManager;
|
||||||
|
@Inject
|
||||||
|
ServiceOfferingDao _serviceOfferingDao;
|
||||||
|
@Inject
|
||||||
|
NetworkModel _networkModel;
|
||||||
|
@Inject
|
||||||
|
GuestOSCategoryDao _guestOSCategoryDao;
|
||||||
|
@Inject
|
||||||
|
GuestOSDao _guestOSDao;
|
||||||
|
@Inject
|
||||||
|
HostDao _hostDao;
|
||||||
|
@Inject
|
||||||
|
DataStoreManager _dataStoreMgr;
|
||||||
|
@Inject
|
||||||
|
EndPointSelector _ep;
|
||||||
|
@Inject
|
||||||
|
VolumeOrchestrationService _volumeMgr;
|
||||||
|
|
||||||
|
public final static String CONFIGDRIVEFILENAME = "configdrive.iso";
|
||||||
|
public final static String CONFIGDRIVEDIR= "ConfigDrive";
|
||||||
|
public final static Integer CONFIGDRIVEDISKSEQ= new Integer(4);
|
||||||
|
|
||||||
|
private boolean canHandle(TrafficType trafficType) {
|
||||||
|
return trafficType.equals(TrafficType.Guest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean start() {
|
||||||
|
VirtualMachine.State.getStateMachine().registerListener(this);
|
||||||
|
return super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException,
|
||||||
|
InsufficientCapacityException {
|
||||||
|
return canHandle(offering.getTrafficType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException,
|
||||||
|
InsufficientCapacityException, ResourceUnavailableException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) {
|
||||||
|
if (!nic.isDefaultNic()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Remove form secondary storage
|
||||||
|
DataStore secondaryStore = _dataStoreMgr.getImageStore(network.getDataCenterId());
|
||||||
|
|
||||||
|
String isoFile = "/" + CONFIGDRIVEDIR + "/" + vm.getInstanceName()+ "/" + CONFIGDRIVEFILENAME;
|
||||||
|
HandleConfigDriveIsoCommand deleteCommand = new HandleConfigDriveIsoCommand(vm.getVmData(),
|
||||||
|
vm.getConfigDriveLabel(), secondaryStore.getTO(), isoFile, false, false);
|
||||||
|
// Delete the ISO on the secondary store
|
||||||
|
EndPoint endpoint = _ep.select(secondaryStore);
|
||||||
|
if (endpoint == null) {
|
||||||
|
s_logger.error(String.format("Secondary store: %s not available", secondaryStore.getName()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Answer answer = endpoint.sendMessage(deleteCommand);
|
||||||
|
return answer.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException {
|
||||||
|
return true; // assume that the agent will remove userdata etc
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean destroy(Network config, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
|
||||||
|
return true; // assume that the agent will remove userdata etc
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Provider getProvider() {
|
||||||
|
return Provider.ConfigDrive;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Service, Map<Capability, String>> getCapabilities() {
|
||||||
|
return capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Service, Map<Capability, String>> setCapabilities() {
|
||||||
|
Map<Service, Map<Capability, String>> capabilities = new HashMap<>();
|
||||||
|
capabilities.put(Service.UserData, null);
|
||||||
|
return capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady(PhysicalNetworkServiceProvider provider) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canEnableIndividualServices() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addPasswordAndUserdata(Network network, NicProfile nic, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context)
|
||||||
|
throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
|
||||||
|
UserVmDetailVO vmDetailSshKey = _userVmDetailsDao.findDetail(profile.getId(), "SSH.PublicKey");
|
||||||
|
return (canHandle(network.getTrafficType()) && updateConfigDrive(profile,
|
||||||
|
(vmDetailSshKey!=null?vmDetailSshKey.getValue():null)))
|
||||||
|
&& updateConfigDriveIso(network, profile, dest.getHost(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean savePassword(Network network, NicProfile nic, VirtualMachineProfile profile) throws ResourceUnavailableException {
|
||||||
|
if (!(canHandle(network.getTrafficType()) && updateConfigDrive(profile, (String) profile.getParameter(VirtualMachineProfile.Param.VmSshPubKey)))) return false;
|
||||||
|
return updateConfigDriveIso(network, profile, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean saveSSHKey(Network network, NicProfile nic, VirtualMachineProfile vm, String sshPublicKey) throws ResourceUnavailableException {
|
||||||
|
if (!(canHandle(network.getTrafficType()) && updateConfigDrive(vm, sshPublicKey))) return false;
|
||||||
|
return updateConfigDriveIso(network, vm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean saveUserData(Network network, NicProfile nic, VirtualMachineProfile profile) throws ResourceUnavailableException {
|
||||||
|
if (!(canHandle(network.getTrafficType()) && updateConfigDrive(profile, (String) profile.getParameter(VirtualMachineProfile.Param.VmSshPubKey)))) return false;
|
||||||
|
return updateConfigDriveIso(network, profile, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verifyServicesCombination(Set<Service> services) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preStateTransitionEvent(VirtualMachine.State oldState, VirtualMachine.Event event, VirtualMachine.State newState, VirtualMachine vo, boolean status, Object opaque) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean postStateTransitionEvent(StateMachine2.Transition<VirtualMachine.State, VirtualMachine.Event> transition, VirtualMachine vo, boolean status, Object opaque) {
|
||||||
|
if (transition.getToState().equals(VirtualMachine.State.Expunging) && transition.getEvent().equals(VirtualMachine.Event.ExpungeOperation)) {
|
||||||
|
Nic nic = _networkModel.getDefaultNic(vo.getId());
|
||||||
|
try {
|
||||||
|
if (nic != null) {
|
||||||
|
final Network network = _networkMgr.getNetwork(nic.getNetworkId());
|
||||||
|
final UserDataServiceProvider userDataUpdateProvider = _networkModel.getUserDataUpdateProvider(network);
|
||||||
|
final Provider provider = userDataUpdateProvider.getProvider();
|
||||||
|
if (provider.equals(Provider.ConfigDrive)) {
|
||||||
|
// Delete config drive ISO on destroy
|
||||||
|
DataStore secondaryStore = _dataStoreMgr.getImageStore(vo.getDataCenterId());
|
||||||
|
String isoFile = "/" + CONFIGDRIVEDIR + "/" + vo.getInstanceName() + "/" + CONFIGDRIVEFILENAME;
|
||||||
|
HandleConfigDriveIsoCommand deleteCommand = new HandleConfigDriveIsoCommand(null,
|
||||||
|
null, secondaryStore.getTO(), isoFile, false, false);
|
||||||
|
EndPoint endpoint = _ep.select(secondaryStore);
|
||||||
|
if (endpoint == null) {
|
||||||
|
s_logger.error(String.format("Secondary store: %s not available", secondaryStore.getName()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Answer answer = endpoint.sendMessage(deleteCommand);
|
||||||
|
if (!answer.getResult()) {
|
||||||
|
s_logger.error(String.format("Update ISO failed, details: %s", answer.getDetails()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (UnsupportedServiceException usse) {}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prepareMigration(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) {
|
||||||
|
if (nic.isDefaultNic() && _networkModel.getUserDataUpdateProvider(network).getProvider().equals(Provider.ConfigDrive)) {
|
||||||
|
s_logger.trace(String.format("[prepareMigration] for vm: %s", vm.getInstanceName()));
|
||||||
|
DataStore secondaryStore = _dataStoreMgr.getImageStore(network.getDataCenterId());
|
||||||
|
configureConfigDriveDisk(vm, secondaryStore);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollbackMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commitMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean updateConfigDriveIso(Network network, VirtualMachineProfile profile, boolean update) throws ResourceUnavailableException {
|
||||||
|
return updateConfigDriveIso(network, profile, null, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean updateConfigDriveIso(Network network, VirtualMachineProfile profile, Host host, boolean update) throws ResourceUnavailableException {
|
||||||
|
Integer deviceKey = null;
|
||||||
|
Long hostId;
|
||||||
|
if (host == null) {
|
||||||
|
hostId = (profile.getVirtualMachine().getHostId() == null ? profile.getVirtualMachine().getLastHostId(): profile.getVirtualMachine().getHostId());
|
||||||
|
} else {
|
||||||
|
hostId = host.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
DataStore secondaryStore = _dataStoreMgr.getImageStore(network.getDataCenterId());
|
||||||
|
// Detach the existing ISO file if the machine is running
|
||||||
|
if (update && profile.getVirtualMachine().getState().equals(VirtualMachine.State.Running)) {
|
||||||
|
s_logger.debug("Detach config drive ISO for vm " + profile.getInstanceName() + " in host " + _hostDao.findById(hostId));
|
||||||
|
deviceKey = detachIso(secondaryStore, profile.getInstanceName(), hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create/Update the iso on the secondary store
|
||||||
|
s_logger.debug(String.format("%s config drive ISO for vm %s in host %s",
|
||||||
|
(update?"update":"create"), profile.getInstanceName(), _hostDao.findById(hostId).getName()));
|
||||||
|
EndPoint endpoint = _ep.select(secondaryStore);
|
||||||
|
if (endpoint == null )
|
||||||
|
throw new ResourceUnavailableException(String.format("%s failed, secondary store not available",
|
||||||
|
(update?"Update":"Create")),secondaryStore.getClass(),secondaryStore.getId());
|
||||||
|
String isoPath = CONFIGDRIVEDIR + "/" + profile.getInstanceName() + "/" + CONFIGDRIVEFILENAME;
|
||||||
|
HandleConfigDriveIsoCommand configDriveIsoCommand = new HandleConfigDriveIsoCommand(profile.getVmData(),
|
||||||
|
profile.getConfigDriveLabel(), secondaryStore.getTO(), isoPath, true, update);
|
||||||
|
Answer createIsoAnswer = endpoint.sendMessage(configDriveIsoCommand);
|
||||||
|
if (!createIsoAnswer.getResult()) {
|
||||||
|
throw new ResourceUnavailableException(String.format("%s ISO failed, details: %s",
|
||||||
|
(update?"Update":"Create"), createIsoAnswer.getDetails()),ConfigDriveNetworkElement.class,0L);
|
||||||
|
}
|
||||||
|
configureConfigDriveDisk(profile, secondaryStore);
|
||||||
|
|
||||||
|
// Re-attach the ISO if the machine is running
|
||||||
|
if (update && profile.getVirtualMachine().getState().equals(VirtualMachine.State.Running)) {
|
||||||
|
s_logger.debug("Re-attach config drive ISO for vm " + profile.getInstanceName() + " in host " + _hostDao.findById(hostId));
|
||||||
|
attachIso(secondaryStore, profile.getInstanceName(), hostId, deviceKey);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureConfigDriveDisk(VirtualMachineProfile profile, DataStore secondaryStore) {
|
||||||
|
boolean isoAvailable = false;
|
||||||
|
String isoPath = CONFIGDRIVEDIR + "/" + profile.getInstanceName() + "/" + CONFIGDRIVEFILENAME;
|
||||||
|
for (DiskTO dataTo : profile.getDisks()) {
|
||||||
|
if (dataTo.getPath().equals(isoPath)) {
|
||||||
|
isoAvailable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isoAvailable) {
|
||||||
|
TemplateObjectTO dataTO = new TemplateObjectTO();
|
||||||
|
dataTO.setDataStore(secondaryStore.getTO());
|
||||||
|
dataTO.setUuid(profile.getUuid());
|
||||||
|
dataTO.setPath(isoPath);
|
||||||
|
dataTO.setFormat(Storage.ImageFormat.ISO);
|
||||||
|
|
||||||
|
profile.addDisk(new DiskTO(dataTO, CONFIGDRIVEDISKSEQ.longValue(), isoPath, Volume.Type.ISO));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean updateConfigDrive(VirtualMachineProfile profile, String publicKey) {
|
||||||
|
UserVmVO vm = _userVmDao.findById(profile.getId());
|
||||||
|
if (vm.getType() != VirtualMachine.Type.User) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// add/update userdata and/or password info into vm profile
|
||||||
|
Nic defaultNic = _networkModel.getDefaultNic(vm.getId());
|
||||||
|
if (defaultNic != null) {
|
||||||
|
final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText();
|
||||||
|
final String zoneName = _dcDao.findById(vm.getDataCenterId()).getName();
|
||||||
|
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
|
||||||
|
|
||||||
|
List<String[]> vmData = _networkModel.generateVmData(vm.getUserData(), serviceOffering, zoneName, vm.getInstanceName(), vm.getId(),
|
||||||
|
publicKey, (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows);
|
||||||
|
profile.setVmData(vmData);
|
||||||
|
profile.setConfigDriveLabel(VirtualMachineManager.VmConfigDriveLabel.value());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer detachIso (DataStore secondaryStore, String instanceName, Long hostId) throws ResourceUnavailableException {
|
||||||
|
String isoPath = CONFIGDRIVEDIR + "/" + instanceName + "/" + CONFIGDRIVEFILENAME;
|
||||||
|
AttachIsoCommand isoCommand = new AttachIsoCommand(instanceName, secondaryStore.getUri() + "/" + isoPath, false, CONFIGDRIVEDISKSEQ, true);
|
||||||
|
isoCommand.setStoreUrl(secondaryStore.getUri());
|
||||||
|
Answer attachIsoAnswer = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
attachIsoAnswer = _agentManager.send(hostId, isoCommand);
|
||||||
|
} catch (OperationTimedoutException e) {
|
||||||
|
throw new ResourceUnavailableException("Detach ISO failed: " + e.getMessage(), ConfigDriveNetworkElement.class, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!attachIsoAnswer.getResult()) {
|
||||||
|
throw new ResourceUnavailableException("Detach ISO failed: " + attachIsoAnswer.getDetails(), ConfigDriveNetworkElement.class, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachIsoAnswer instanceof AttachIsoAnswer) {
|
||||||
|
return ((AttachIsoAnswer)attachIsoAnswer).getDeviceKey();
|
||||||
|
} else {
|
||||||
|
return CONFIGDRIVEDISKSEQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachIso (DataStore secondaryStore, String instanceName, Long hostId, Integer deviceKey) throws ResourceUnavailableException {
|
||||||
|
String isoPath = CONFIGDRIVEDIR + "/" + instanceName + "/" + CONFIGDRIVEFILENAME;
|
||||||
|
AttachIsoCommand isoCommand = new AttachIsoCommand(instanceName, secondaryStore.getUri() + "/" + isoPath, true);
|
||||||
|
isoCommand.setStoreUrl(secondaryStore.getUri());
|
||||||
|
isoCommand.setDeviceKey(deviceKey);
|
||||||
|
Answer attachIsoAnswer = null;
|
||||||
|
try {
|
||||||
|
attachIsoAnswer = _agentManager.send(hostId, isoCommand);
|
||||||
|
} catch (OperationTimedoutException e) {
|
||||||
|
throw new ResourceUnavailableException("Attach ISO failed: " + e.getMessage() ,ConfigDriveNetworkElement.class,0L);
|
||||||
|
}
|
||||||
|
if (!attachIsoAnswer.getResult()) {
|
||||||
|
throw new ResourceUnavailableException("Attach ISO failed: " + attachIsoAnswer.getDetails(),ConfigDriveNetworkElement.class,0L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -33,7 +33,6 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
@ -48,7 +47,6 @@ import org.apache.cloudstack.context.CallContext;
|
|||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
||||||
|
|
||||||
import com.cloud.configuration.Config;
|
import com.cloud.configuration.Config;
|
||||||
import com.cloud.configuration.Resource.ResourceType;
|
import com.cloud.configuration.Resource.ResourceType;
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
@ -206,7 +204,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||||||
private List<VpcProvider> vpcElements = null;
|
private List<VpcProvider> vpcElements = null;
|
||||||
private final List<Service> nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall);
|
private final List<Service> nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall);
|
||||||
private final List<Provider> supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler,
|
private final List<Provider> supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler,
|
||||||
Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.NuageVsp, Provider.BigSwitchBcf);
|
Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.NuageVsp, Provider.BigSwitchBcf, Provider.ConfigDrive);
|
||||||
|
|
||||||
int _cleanupInterval;
|
int _cleanupInterval;
|
||||||
int _maxNetworks;
|
int _maxNetworks;
|
||||||
|
|||||||
@ -16,6 +16,8 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.vm;
|
package com.cloud.vm;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -3996,6 +3998,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
protected String validateUserData(String userData, HTTPMethod httpmethod) {
|
protected String validateUserData(String userData, HTTPMethod httpmethod) {
|
||||||
byte[] decodedUserData = null;
|
byte[] decodedUserData = null;
|
||||||
if (userData != null) {
|
if (userData != null) {
|
||||||
|
|
||||||
|
if (userData.contains("%")) {
|
||||||
|
try {
|
||||||
|
userData = URLDecoder.decode(userData, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new InvalidParameterValueException("Url decoding of userdata failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!Base64.isBase64(userData)) {
|
if (!Base64.isBase64(userData)) {
|
||||||
throw new InvalidParameterValueException("User data is not base64 encoded");
|
throw new InvalidParameterValueException("User data is not base64 encoded");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,272 @@
|
|||||||
|
// 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.network.element;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.hasEntry;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.xerces.impl.dv.util.Base64;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
|
||||||
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.HandleConfigDriveIsoCommand;
|
||||||
|
import com.cloud.dc.DataCenterVO;
|
||||||
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
|
import com.cloud.deploy.DeployDestination;
|
||||||
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.host.HostVO;
|
||||||
|
import com.cloud.host.dao.HostDao;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.NetworkModelImpl;
|
||||||
|
import com.cloud.network.Networks;
|
||||||
|
import com.cloud.network.dao.NetworkDao;
|
||||||
|
import com.cloud.network.dao.NetworkServiceMapDao;
|
||||||
|
import com.cloud.network.dao.NetworkVO;
|
||||||
|
import com.cloud.offerings.NetworkOfferingVO;
|
||||||
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
|
import com.cloud.storage.GuestOSCategoryVO;
|
||||||
|
import com.cloud.storage.GuestOSVO;
|
||||||
|
import com.cloud.storage.dao.GuestOSCategoryDao;
|
||||||
|
import com.cloud.storage.dao.GuestOSDao;
|
||||||
|
import com.cloud.utils.fsm.NoTransitionException;
|
||||||
|
import com.cloud.utils.fsm.StateListener;
|
||||||
|
import com.cloud.utils.fsm.StateMachine2;
|
||||||
|
import com.cloud.vm.Nic;
|
||||||
|
import com.cloud.vm.NicProfile;
|
||||||
|
import com.cloud.vm.UserVmDetailVO;
|
||||||
|
import com.cloud.vm.UserVmVO;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
|
import com.cloud.vm.VirtualMachineProfileImpl;
|
||||||
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
|
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||||
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
|
|
||||||
|
public class ConfigDriveNetworkElementTest {
|
||||||
|
|
||||||
|
public static final String CLOUD_ID = "xx";
|
||||||
|
public static final String PUBLIC_KEY = "publicKey";
|
||||||
|
public static final String PASSWORD = "password";
|
||||||
|
public static final long NETWORK_ID = 1L;
|
||||||
|
private final long DATACENTERID = NETWORK_ID;
|
||||||
|
private final String ZONENAME = "zone1";
|
||||||
|
private final String VMINSTANCENAME = "vm_name";
|
||||||
|
private final String VMOFFERING = "custom_instance";
|
||||||
|
private final long VMID = 30L;
|
||||||
|
private final String VMUSERDATA = "userdata";
|
||||||
|
private final long SOID = 31L;
|
||||||
|
private final long HOSTID = NETWORK_ID;
|
||||||
|
private final String HOSTNAME = "host1";
|
||||||
|
|
||||||
|
@Mock private ConfigurationDao _configDao;
|
||||||
|
@Mock private DataCenterDao _dcDao;
|
||||||
|
@Mock private DataStoreManager _dataStoreMgr;
|
||||||
|
@Mock private GuestOSCategoryDao _guestOSCategoryDao ;
|
||||||
|
@Mock private GuestOSDao _guestOSDao;
|
||||||
|
@Mock private HostDao _hostDao;
|
||||||
|
@Mock private ServiceOfferingDao _serviceOfferingDao;
|
||||||
|
@Mock private UserVmDao _vmDao;
|
||||||
|
@Mock private VMInstanceDao _vmInstanceDao;
|
||||||
|
@Mock private UserVmDetailsDao _userVmDetailsDao;
|
||||||
|
@Mock private NetworkDao _networkDao;
|
||||||
|
@Mock private NetworkServiceMapDao _ntwkSrvcDao;
|
||||||
|
|
||||||
|
@Mock private DataCenterVO dataCenterVO;
|
||||||
|
@Mock private DataStore dataStore;
|
||||||
|
@Mock private DeployDestination deployDestination;
|
||||||
|
@Mock private EndPoint endpoint;
|
||||||
|
@Mock private EndPointSelector _ep;
|
||||||
|
@Mock private GuestOSCategoryVO guestOSCategoryVo;
|
||||||
|
@Mock private GuestOSVO guestOSVO;
|
||||||
|
@Mock private HostVO hostVO;
|
||||||
|
@Mock private NetworkVO network;
|
||||||
|
@Mock private Nic nic;
|
||||||
|
@Mock private NicProfile nicp;
|
||||||
|
@Mock private ServiceOfferingVO serviceOfferingVO;
|
||||||
|
@Mock private UserVmVO virtualMachine;
|
||||||
|
|
||||||
|
@InjectMocks private final ConfigDriveNetworkElement _configDrivesNetworkElement = new ConfigDriveNetworkElement();
|
||||||
|
@InjectMocks @Spy private NetworkModelImpl _networkModel = new NetworkModelImpl();
|
||||||
|
|
||||||
|
@org.junit.Before
|
||||||
|
public void setUp() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
_configDrivesNetworkElement._networkModel = _networkModel;
|
||||||
|
|
||||||
|
when(_dataStoreMgr.getImageStore(DATACENTERID)).thenReturn(dataStore);
|
||||||
|
when(_ep.select(dataStore)).thenReturn(endpoint);
|
||||||
|
when(_vmDao.findById(VMID)).thenReturn(virtualMachine);
|
||||||
|
when(_dcDao.findById(DATACENTERID)).thenReturn(dataCenterVO);
|
||||||
|
when(_hostDao.findById(HOSTID)).thenReturn(hostVO);
|
||||||
|
doReturn(nic).when(_networkModel).getDefaultNic(VMID);
|
||||||
|
when(_serviceOfferingDao.findByIdIncludingRemoved(VMID, SOID)).thenReturn(serviceOfferingVO);
|
||||||
|
when(_guestOSDao.findById(anyLong())).thenReturn(guestOSVO);
|
||||||
|
when(_guestOSCategoryDao.findById(anyLong())).thenReturn(guestOSCategoryVo);
|
||||||
|
when(_configDao.getValue("cloud.identifier")).thenReturn(CLOUD_ID);
|
||||||
|
when(network.getDataCenterId()).thenReturn(DATACENTERID);
|
||||||
|
when(guestOSCategoryVo.getName()).thenReturn("Linux");
|
||||||
|
when(dataCenterVO.getName()).thenReturn(ZONENAME);
|
||||||
|
when(serviceOfferingVO.getDisplayText()).thenReturn(VMOFFERING);
|
||||||
|
when(guestOSVO.getCategoryId()).thenReturn(0L);
|
||||||
|
when(virtualMachine.getGuestOSId()).thenReturn(0L);
|
||||||
|
when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User);
|
||||||
|
when(virtualMachine.getId()).thenReturn(VMID);
|
||||||
|
when(virtualMachine.getServiceOfferingId()).thenReturn(SOID);
|
||||||
|
when(virtualMachine.getDataCenterId()).thenReturn(DATACENTERID);
|
||||||
|
when(virtualMachine.getInstanceName()).thenReturn(VMINSTANCENAME);
|
||||||
|
when(virtualMachine.getUserData()).thenReturn(Base64.encode(VMUSERDATA.getBytes()));
|
||||||
|
when(deployDestination.getHost()).thenReturn(hostVO);
|
||||||
|
when(hostVO.getId()).thenReturn(HOSTID);
|
||||||
|
when(nic.isDefaultNic()).thenReturn(true);
|
||||||
|
when(nic.getNetworkId()).thenReturn(NETWORK_ID);
|
||||||
|
when(network.getId()).thenReturn(NETWORK_ID);
|
||||||
|
when(_networkModel.getNetwork(NETWORK_ID)).thenReturn(network);
|
||||||
|
//when(_networkModel.getUserDataUpdateProvider(network)).thenReturn(_configDrivesNetworkElement);
|
||||||
|
|
||||||
|
when(_ntwkSrvcDao.getProviderForServiceInNetwork(NETWORK_ID, Network.Service.UserData)).thenReturn(_configDrivesNetworkElement.getProvider().getName());
|
||||||
|
|
||||||
|
_networkModel.setNetworkElements(Arrays.asList(_configDrivesNetworkElement));
|
||||||
|
_networkModel.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanHandle() throws InsufficientCapacityException, ResourceUnavailableException {
|
||||||
|
final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class);
|
||||||
|
when(ntwkoffer.getTrafficType()).thenReturn(Networks.TrafficType.Guest);
|
||||||
|
assertTrue(_configDrivesNetworkElement.implement(null, ntwkoffer, null,null));
|
||||||
|
|
||||||
|
when(ntwkoffer.getTrafficType()).thenReturn(Networks.TrafficType.Public);
|
||||||
|
assertFalse(_configDrivesNetworkElement.implement(null, ntwkoffer, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void testExpunge() throws NoTransitionException, NoSuchFieldException, IllegalAccessException {
|
||||||
|
final StateMachine2<VirtualMachine.State, VirtualMachine.Event, VirtualMachine> stateMachine = VirtualMachine.State.getStateMachine();
|
||||||
|
|
||||||
|
final Field listenersField = StateMachine2.class.getDeclaredField("_listeners");
|
||||||
|
listenersField.setAccessible(true);
|
||||||
|
List<StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualMachine>> listeners =
|
||||||
|
(List<StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualMachine>>)listenersField.get(stateMachine);
|
||||||
|
|
||||||
|
listeners.clear();
|
||||||
|
|
||||||
|
_configDrivesNetworkElement.start();
|
||||||
|
|
||||||
|
when(virtualMachine.getState()).thenReturn(VirtualMachine.State.Stopped);
|
||||||
|
when(_vmInstanceDao.updateState(VirtualMachine.State.Stopped, VirtualMachine.Event.ExpungeOperation, VirtualMachine.State.Expunging, virtualMachine, null)).thenReturn(true);
|
||||||
|
|
||||||
|
final Answer answer = mock(Answer.class);
|
||||||
|
when(endpoint.sendMessage(any(HandleConfigDriveIsoCommand.class))).thenReturn(answer);
|
||||||
|
when(answer.getResult()).thenReturn(true);
|
||||||
|
|
||||||
|
stateMachine.transitTo(virtualMachine, VirtualMachine.Event.ExpungeOperation, null, _vmInstanceDao);
|
||||||
|
|
||||||
|
ArgumentCaptor<HandleConfigDriveIsoCommand> commandCaptor = ArgumentCaptor.forClass(HandleConfigDriveIsoCommand.class);
|
||||||
|
verify(endpoint, times(1)).sendMessage(commandCaptor.capture());
|
||||||
|
HandleConfigDriveIsoCommand deleteCommand = commandCaptor.getValue();
|
||||||
|
|
||||||
|
assertThat(deleteCommand.isCreate(), is(false));
|
||||||
|
assertThat(deleteCommand.isUpdate(), is(false));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRelease() {
|
||||||
|
final Answer answer = mock(Answer.class);
|
||||||
|
when(endpoint.sendMessage(any(HandleConfigDriveIsoCommand.class))).thenReturn(answer);
|
||||||
|
when(answer.getResult()).thenReturn(true);
|
||||||
|
VirtualMachineProfile profile = new VirtualMachineProfileImpl(virtualMachine, null, serviceOfferingVO, null, null);
|
||||||
|
assertTrue(_configDrivesNetworkElement.release(network, nicp, profile, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCapabilities () {
|
||||||
|
assertThat(_configDrivesNetworkElement.getCapabilities(), hasEntry(Network.Service.UserData, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddPasswordAndUserdata() throws InsufficientCapacityException, ResourceUnavailableException {
|
||||||
|
final Answer answer = mock(Answer.class);
|
||||||
|
final UserVmDetailVO userVmDetailVO = mock(UserVmDetailVO.class);
|
||||||
|
when(endpoint.sendMessage(any(HandleConfigDriveIsoCommand.class))).thenReturn(answer);
|
||||||
|
when(answer.getResult()).thenReturn(true);
|
||||||
|
when(network.getTrafficType()).thenReturn(Networks.TrafficType.Guest);
|
||||||
|
when(virtualMachine.getState()).thenReturn(VirtualMachine.State.Stopped);
|
||||||
|
when(userVmDetailVO.getValue()).thenReturn(PUBLIC_KEY);
|
||||||
|
when(_userVmDetailsDao.findDetail(anyLong(), anyString())).thenReturn(userVmDetailVO);
|
||||||
|
Map<VirtualMachineProfile.Param, Object> parms = Maps.newHashMap();
|
||||||
|
parms.put(VirtualMachineProfile.Param.VmPassword, PASSWORD);
|
||||||
|
parms.put(VirtualMachineProfile.Param.VmSshPubKey, PUBLIC_KEY);
|
||||||
|
VirtualMachineProfile profile = new VirtualMachineProfileImpl(virtualMachine, null, serviceOfferingVO, null, parms);
|
||||||
|
assertTrue(_configDrivesNetworkElement.addPasswordAndUserdata(
|
||||||
|
network, nicp, profile, deployDestination, null));
|
||||||
|
|
||||||
|
ArgumentCaptor<HandleConfigDriveIsoCommand> commandCaptor = ArgumentCaptor.forClass(HandleConfigDriveIsoCommand.class);
|
||||||
|
verify(endpoint, times(1)).sendMessage(commandCaptor.capture());
|
||||||
|
HandleConfigDriveIsoCommand result = commandCaptor.getValue();
|
||||||
|
List<String[]> actualVmData = result.getVmData();
|
||||||
|
|
||||||
|
assertThat(actualVmData, containsInAnyOrder(
|
||||||
|
new String[]{"userdata", "user_data", VMUSERDATA},
|
||||||
|
new String[]{"metadata", "service-offering", VMOFFERING},
|
||||||
|
new String[]{"metadata", "availability-zone", ZONENAME},
|
||||||
|
new String[]{"metadata", "local-hostname", VMINSTANCENAME},
|
||||||
|
new String[]{"metadata", "vm-id", String.valueOf(VMID)},
|
||||||
|
new String[]{"metadata", "instance-id", String.valueOf(VMINSTANCENAME)},
|
||||||
|
new String[]{"metadata", "public-keys", PUBLIC_KEY},
|
||||||
|
new String[]{"metadata", "cloud-identifier", String.format("CloudStack-{%s}", CLOUD_ID)},
|
||||||
|
new String[]{PASSWORD, "vm_password", PASSWORD}
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,8 +17,9 @@
|
|||||||
|
|
||||||
package com.cloud.vm;
|
package com.cloud.vm;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyBoolean;
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
@ -35,6 +36,7 @@ import static org.mockito.Mockito.times;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -45,13 +47,7 @@ import java.util.UUID;
|
|||||||
import com.cloud.dc.VlanVO;
|
import com.cloud.dc.VlanVO;
|
||||||
import com.cloud.dc.dao.VlanDao;
|
import com.cloud.dc.dao.VlanDao;
|
||||||
import com.cloud.network.dao.IPAddressVO;
|
import com.cloud.network.dao.IPAddressVO;
|
||||||
import com.cloud.network.element.UserDataServiceProvider;
|
|
||||||
import com.cloud.storage.Storage;
|
|
||||||
import com.cloud.user.User;
|
|
||||||
import com.cloud.event.dao.UsageEventDao;
|
|
||||||
import com.cloud.uservm.UserVm;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.apache.cloudstack.api.BaseCmd;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
@ -61,6 +57,7 @@ import org.mockito.Spy;
|
|||||||
|
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
import org.apache.cloudstack.acl.ControlledEntity;
|
||||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
|
||||||
@ -72,14 +69,16 @@ import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationSer
|
|||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||||
|
|
||||||
import com.cloud.capacity.CapacityManager;
|
import com.cloud.capacity.CapacityManager;
|
||||||
import com.cloud.configuration.ConfigurationManager;
|
import com.cloud.configuration.ConfigurationManager;
|
||||||
import com.cloud.dc.DataCenterVO;
|
|
||||||
import com.cloud.dc.DataCenter.NetworkType;
|
import com.cloud.dc.DataCenter.NetworkType;
|
||||||
|
import com.cloud.dc.DataCenterVO;
|
||||||
import com.cloud.dc.dao.DataCenterDao;
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
import com.cloud.deploy.DeployDestination;
|
import com.cloud.deploy.DeployDestination;
|
||||||
|
import com.cloud.event.dao.UsageEventDao;
|
||||||
import com.cloud.exception.ConcurrentOperationException;
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
import com.cloud.exception.InsufficientCapacityException;
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
@ -96,11 +95,13 @@ import com.cloud.network.NetworkModel;
|
|||||||
import com.cloud.network.dao.IPAddressDao;
|
import com.cloud.network.dao.IPAddressDao;
|
||||||
import com.cloud.network.dao.NetworkDao;
|
import com.cloud.network.dao.NetworkDao;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
|
import com.cloud.network.element.UserDataServiceProvider;
|
||||||
import com.cloud.offering.ServiceOffering;
|
import com.cloud.offering.ServiceOffering;
|
||||||
import com.cloud.offerings.NetworkOfferingVO;
|
import com.cloud.offerings.NetworkOfferingVO;
|
||||||
import com.cloud.offerings.dao.NetworkOfferingDao;
|
import com.cloud.offerings.dao.NetworkOfferingDao;
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
import com.cloud.service.dao.ServiceOfferingDao;
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.Storage.ImageFormat;
|
import com.cloud.storage.Storage.ImageFormat;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
@ -112,9 +113,11 @@ import com.cloud.user.AccountManager;
|
|||||||
import com.cloud.user.AccountService;
|
import com.cloud.user.AccountService;
|
||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
import com.cloud.user.ResourceLimitService;
|
import com.cloud.user.ResourceLimitService;
|
||||||
|
import com.cloud.user.User;
|
||||||
import com.cloud.user.UserVO;
|
import com.cloud.user.UserVO;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
import com.cloud.user.dao.UserDao;
|
import com.cloud.user.dao.UserDao;
|
||||||
|
import com.cloud.uservm.UserVm;
|
||||||
import com.cloud.utils.db.EntityManager;
|
import com.cloud.utils.db.EntityManager;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.vm.VirtualMachine.State;
|
import com.cloud.vm.VirtualMachine.State;
|
||||||
@ -123,7 +126,6 @@ import com.cloud.vm.dao.UserVmDao;
|
|||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
|
||||||
|
|
||||||
public class UserVmManagerTest {
|
public class UserVmManagerTest {
|
||||||
|
|
||||||
@ -1084,4 +1086,14 @@ public class UserVmManagerTest {
|
|||||||
assertTrue("validate return the value with padding", encodedUserdataWithPadding.equals(_userVmMgr.validateUserData(encodedUserdataWithPadding, BaseCmd.HTTPMethod.GET)));
|
assertTrue("validate return the value with padding", encodedUserdataWithPadding.equals(_userVmMgr.validateUserData(encodedUserdataWithPadding, BaseCmd.HTTPMethod.GET)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateUrlEncodedBase64() throws UnsupportedEncodingException {
|
||||||
|
// fo should be encoded in base64 either as Zm8 or Zm8=
|
||||||
|
String encodedUserdata = "Zm+8/w8=";
|
||||||
|
String urlEncodedUserdata = java.net.URLEncoder.encode(encodedUserdata, "UTF-8");
|
||||||
|
|
||||||
|
// Verify that we accept both but return the padded version
|
||||||
|
assertEquals("validate return the value with padding", encodedUserdata, _userVmMgr.validateUserData(encodedUserdata, BaseCmd.HTTPMethod.GET));
|
||||||
|
assertEquals("validate return the value with padding", encodedUserdata, _userVmMgr.validateUserData(urlEncodedUserdata, BaseCmd.HTTPMethod.GET));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,21 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.storage.resource;
|
package org.apache.cloudstack.storage.resource;
|
||||||
|
|
||||||
|
import static com.cloud.network.NetworkModel.CONFIGDATA_CONTENT;
|
||||||
|
import static com.cloud.network.NetworkModel.CONFIGDATA_DIR;
|
||||||
|
import static com.cloud.network.NetworkModel.CONFIGDATA_FILE;
|
||||||
|
import static com.cloud.network.NetworkModel.METATDATA_DIR;
|
||||||
|
import static com.cloud.network.NetworkModel.PASSWORD_DIR;
|
||||||
|
import static com.cloud.network.NetworkModel.PASSWORD_FILE;
|
||||||
|
import static com.cloud.network.NetworkModel.PUBLIC_KEYS_FILE;
|
||||||
|
import static com.cloud.network.NetworkModel.USERDATA_DIR;
|
||||||
|
import static com.cloud.network.NetworkModel.USERDATA_FILE;
|
||||||
|
import static com.cloud.utils.StringUtils.join;
|
||||||
|
import static com.cloud.utils.storage.S3.S3Utils.putFile;
|
||||||
|
import static java.lang.String.format;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static org.apache.commons.lang.StringUtils.substringAfterLast;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -29,6 +44,8 @@ import java.io.UnsupportedEncodingException;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -36,7 +53,68 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.HttpContentCompressor;
|
||||||
|
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||||
|
import io.netty.handler.logging.LogLevel;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.NameValuePair;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.utils.URLEncodedUtils;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.format.ISODateTimeFormat;
|
||||||
|
|
||||||
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.framework.security.keystore.KeystoreManager;
|
||||||
|
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
||||||
|
import org.apache.cloudstack.storage.command.CopyCommand;
|
||||||
|
import org.apache.cloudstack.storage.command.DeleteCommand;
|
||||||
|
import org.apache.cloudstack.storage.command.DownloadCommand;
|
||||||
|
import org.apache.cloudstack.storage.command.DownloadProgressCommand;
|
||||||
|
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
|
||||||
|
import org.apache.cloudstack.storage.command.UploadStatusAnswer;
|
||||||
|
import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus;
|
||||||
|
import org.apache.cloudstack.storage.command.UploadStatusCommand;
|
||||||
|
import org.apache.cloudstack.storage.template.DownloadManager;
|
||||||
|
import org.apache.cloudstack.storage.template.DownloadManagerImpl;
|
||||||
|
import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser;
|
||||||
|
import org.apache.cloudstack.storage.template.UploadEntity;
|
||||||
|
import org.apache.cloudstack.storage.template.UploadManager;
|
||||||
|
import org.apache.cloudstack.storage.template.UploadManagerImpl;
|
||||||
|
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
||||||
|
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||||
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
|
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||||
|
import org.apache.cloudstack.utils.security.DigestHelper;
|
||||||
|
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.agent.api.CheckHealthAnswer;
|
import com.cloud.agent.api.CheckHealthAnswer;
|
||||||
import com.cloud.agent.api.CheckHealthCommand;
|
import com.cloud.agent.api.CheckHealthCommand;
|
||||||
@ -45,6 +123,7 @@ import com.cloud.agent.api.ComputeChecksumCommand;
|
|||||||
import com.cloud.agent.api.DeleteSnapshotsDirCommand;
|
import com.cloud.agent.api.DeleteSnapshotsDirCommand;
|
||||||
import com.cloud.agent.api.GetStorageStatsAnswer;
|
import com.cloud.agent.api.GetStorageStatsAnswer;
|
||||||
import com.cloud.agent.api.GetStorageStatsCommand;
|
import com.cloud.agent.api.GetStorageStatsCommand;
|
||||||
|
import com.cloud.agent.api.HandleConfigDriveIsoCommand;
|
||||||
import com.cloud.agent.api.PingCommand;
|
import com.cloud.agent.api.PingCommand;
|
||||||
import com.cloud.agent.api.PingStorageCommand;
|
import com.cloud.agent.api.PingStorageCommand;
|
||||||
import com.cloud.agent.api.ReadyAnswer;
|
import com.cloud.agent.api.ReadyAnswer;
|
||||||
@ -82,6 +161,7 @@ import com.cloud.host.Host;
|
|||||||
import com.cloud.host.Host.Type;
|
import com.cloud.host.Host.Type;
|
||||||
import com.cloud.configuration.Resource;
|
import com.cloud.configuration.Resource;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
|
import com.cloud.network.NetworkModel;
|
||||||
import com.cloud.resource.ServerResourceBase;
|
import com.cloud.resource.ServerResourceBase;
|
||||||
import com.cloud.storage.DataStoreRole;
|
import com.cloud.storage.DataStoreRole;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
@ -109,63 +189,7 @@ import com.cloud.utils.script.OutputInterpreter;
|
|||||||
import com.cloud.utils.script.Script;
|
import com.cloud.utils.script.Script;
|
||||||
import com.cloud.utils.storage.S3.S3Utils;
|
import com.cloud.utils.storage.S3.S3Utils;
|
||||||
import com.cloud.vm.SecondaryStorageVm;
|
import com.cloud.vm.SecondaryStorageVm;
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import io.netty.channel.ChannelInitializer;
|
|
||||||
import io.netty.channel.ChannelPipeline;
|
|
||||||
import io.netty.channel.EventLoopGroup;
|
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
|
||||||
import io.netty.channel.socket.SocketChannel;
|
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
|
||||||
import io.netty.handler.codec.http.HttpContentCompressor;
|
|
||||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
|
||||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
|
||||||
import io.netty.handler.logging.LogLevel;
|
|
||||||
import io.netty.handler.logging.LoggingHandler;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.framework.security.keystore.KeystoreManager;
|
|
||||||
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
|
||||||
import org.apache.cloudstack.storage.command.CopyCommand;
|
|
||||||
import org.apache.cloudstack.storage.command.DeleteCommand;
|
|
||||||
import org.apache.cloudstack.storage.command.DownloadCommand;
|
|
||||||
import org.apache.cloudstack.storage.command.DownloadProgressCommand;
|
|
||||||
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
|
|
||||||
import org.apache.cloudstack.storage.command.UploadStatusAnswer;
|
|
||||||
import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus;
|
|
||||||
import org.apache.cloudstack.storage.command.UploadStatusCommand;
|
|
||||||
import org.apache.cloudstack.storage.template.DownloadManager;
|
|
||||||
import org.apache.cloudstack.storage.template.DownloadManagerImpl;
|
|
||||||
import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser;
|
|
||||||
import org.apache.cloudstack.storage.template.UploadEntity;
|
|
||||||
import org.apache.cloudstack.storage.template.UploadManager;
|
|
||||||
import org.apache.cloudstack.storage.template.UploadManagerImpl;
|
|
||||||
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
|
||||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
|
||||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
|
||||||
import org.apache.cloudstack.utils.security.DigestHelper;
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.apache.http.HttpEntity;
|
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
import org.apache.http.NameValuePair;
|
|
||||||
import org.apache.http.client.HttpClient;
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.apache.http.client.utils.URLEncodedUtils;
|
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.format.ISODateTimeFormat;
|
|
||||||
|
|
||||||
import static com.cloud.utils.StringUtils.join;
|
|
||||||
import static com.cloud.utils.storage.S3.S3Utils.putFile;
|
|
||||||
import static java.lang.String.format;
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
import static org.apache.commons.lang.StringUtils.substringAfterLast;
|
|
||||||
|
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
|
|
||||||
@ -176,6 +200,16 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
|||||||
private static final String TEMPLATE_ROOT_DIR = "template/tmpl";
|
private static final String TEMPLATE_ROOT_DIR = "template/tmpl";
|
||||||
private static final String VOLUME_ROOT_DIR = "volumes";
|
private static final String VOLUME_ROOT_DIR = "volumes";
|
||||||
private static final String POST_UPLOAD_KEY_LOCATION = "/etc/cloudstack/agent/ms-psk";
|
private static final String POST_UPLOAD_KEY_LOCATION = "/etc/cloudstack/agent/ms-psk";
|
||||||
|
private static final String cloudStackConfigDriveName = "/cloudstack/";
|
||||||
|
private static final String openStackConfigDriveName = "/openstack/latest/";
|
||||||
|
|
||||||
|
private static final Map<String, String> updatableConfigData = Maps.newHashMap();
|
||||||
|
static {
|
||||||
|
|
||||||
|
updatableConfigData.put(PUBLIC_KEYS_FILE, METATDATA_DIR);
|
||||||
|
updatableConfigData.put(USERDATA_FILE, USERDATA_DIR);
|
||||||
|
updatableConfigData.put(PASSWORD_FILE, PASSWORD_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
int _timeout;
|
int _timeout;
|
||||||
|
|
||||||
@ -291,6 +325,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
|||||||
return execute((DeleteCommand)cmd);
|
return execute((DeleteCommand)cmd);
|
||||||
} else if (cmd instanceof UploadStatusCommand) {
|
} else if (cmd instanceof UploadStatusCommand) {
|
||||||
return execute((UploadStatusCommand)cmd);
|
return execute((UploadStatusCommand)cmd);
|
||||||
|
} else if (cmd instanceof HandleConfigDriveIsoCommand) {
|
||||||
|
return execute((HandleConfigDriveIsoCommand)cmd);
|
||||||
} else if (cmd instanceof GetDatadisksCommand) {
|
} else if (cmd instanceof GetDatadisksCommand) {
|
||||||
return execute((GetDatadisksCommand)cmd);
|
return execute((GetDatadisksCommand)cmd);
|
||||||
} else if (cmd instanceof CreateDatadiskTemplateCommand) {
|
} else if (cmd instanceof CreateDatadiskTemplateCommand) {
|
||||||
@ -300,6 +336,306 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Answer execute(HandleConfigDriveIsoCommand cmd) {
|
||||||
|
|
||||||
|
if (cmd.isCreate()) {
|
||||||
|
s_logger.debug(String.format("VMdata %s, attach = %s", cmd.getVmData(), cmd.isCreate()));
|
||||||
|
if(cmd.getVmData() == null) return new Answer(cmd, false, "No Vmdata available");
|
||||||
|
String nfsMountPoint = getRootDir(cmd.getDestStore().getUrl(), _nfsVersion);
|
||||||
|
File isoFile = new File(nfsMountPoint, cmd.getIsoFile());
|
||||||
|
if(isoFile.exists()) {
|
||||||
|
if (!cmd.isUpdate()) {
|
||||||
|
return new Answer(cmd, true, "ISO already available");
|
||||||
|
} else {
|
||||||
|
// Find out if we have to recover the password/ssh-key from the already available ISO.
|
||||||
|
try {
|
||||||
|
List<String[]> recoveredVmData = recoverVmData(isoFile);
|
||||||
|
for (String[] vmDataEntry : cmd.getVmData()) {
|
||||||
|
if (updatableConfigData.containsKey(vmDataEntry[CONFIGDATA_FILE])
|
||||||
|
&& updatableConfigData.get(vmDataEntry[CONFIGDATA_FILE]).equals(vmDataEntry[CONFIGDATA_DIR])) {
|
||||||
|
updateVmData(recoveredVmData, vmDataEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.setVmData(recoveredVmData);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return new Answer(cmd, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return createConfigDriveIsoForVM(cmd);
|
||||||
|
} else {
|
||||||
|
DataStoreTO dstore = cmd.getDestStore();
|
||||||
|
if (dstore instanceof NfsTO) {
|
||||||
|
NfsTO nfs = (NfsTO) dstore;
|
||||||
|
String relativeTemplatePath = new File(cmd.getIsoFile()).getParent();
|
||||||
|
String nfsMountPoint = getRootDir(nfs.getUrl(), _nfsVersion);
|
||||||
|
File tmpltPath = new File(nfsMountPoint, relativeTemplatePath);
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(tmpltPath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return new Answer(cmd, e);
|
||||||
|
}
|
||||||
|
return new Answer(cmd);
|
||||||
|
} else {
|
||||||
|
return new Answer(cmd, false, "Not implemented yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateVmData(List<String[]> recoveredVmData, String[] vmDataEntry) {
|
||||||
|
for (String[] recoveredEntry : recoveredVmData) {
|
||||||
|
if (recoveredEntry[CONFIGDATA_DIR].equals(vmDataEntry[CONFIGDATA_DIR])
|
||||||
|
&& recoveredEntry[CONFIGDATA_FILE].equals(vmDataEntry[CONFIGDATA_FILE])) {
|
||||||
|
recoveredEntry[CONFIGDATA_CONTENT] = vmDataEntry[CONFIGDATA_CONTENT];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recoveredVmData.add(vmDataEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String[]> recoverVmData(File isoFile) throws IOException {
|
||||||
|
String tempDirName = null;
|
||||||
|
List<String[]> recoveredVmData = Lists.newArrayList();
|
||||||
|
boolean mounted = false;
|
||||||
|
try {
|
||||||
|
Path tempDir = java.nio.file.Files.createTempDirectory("ConfigDrive");
|
||||||
|
tempDirName = tempDir.toString();
|
||||||
|
|
||||||
|
// Unpack the current config drive file
|
||||||
|
Script command = new Script(!_inSystemVM, "mount", _timeout, s_logger);
|
||||||
|
command.add("-o", "loop");
|
||||||
|
command.add(isoFile.getAbsolutePath());
|
||||||
|
command.add(tempDirName);
|
||||||
|
String result = command.execute();
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
String errMsg = "Unable to mount " + isoFile.getAbsolutePath() + " at " + tempDirName + " due to " + result;
|
||||||
|
s_logger.error(errMsg);
|
||||||
|
throw new IOException(errMsg);
|
||||||
|
}
|
||||||
|
mounted = true;
|
||||||
|
|
||||||
|
|
||||||
|
// Scan directory structure
|
||||||
|
for (File configDirectory: (new File(tempDirName, "cloudstack")).listFiles()){
|
||||||
|
for (File configFile: configDirectory.listFiles()) {
|
||||||
|
recoveredVmData.add(new String[]{configDirectory.getName(),
|
||||||
|
Files.getNameWithoutExtension(configFile.getName()),
|
||||||
|
Files.readFirstLine(configFile, Charset.defaultCharset())});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (mounted) {
|
||||||
|
Script command = new Script(!_inSystemVM, "umount", _timeout, s_logger);
|
||||||
|
command.add(tempDirName);
|
||||||
|
String result = command.execute();
|
||||||
|
if (result != null) {
|
||||||
|
s_logger.warn("Unable to umount " + tempDirName + " due to " + result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(new File(tempDirName));
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
s_logger.warn("Failed to delete ConfigDrive temporary directory: " + tempDirName, ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return recoveredVmData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Answer createConfigDriveIsoForVM(HandleConfigDriveIsoCommand cmd) {
|
||||||
|
//create folder for the VM
|
||||||
|
if (cmd.getVmData() != null) {
|
||||||
|
|
||||||
|
Path tempDir = null;
|
||||||
|
String tempDirName = null;
|
||||||
|
try {
|
||||||
|
tempDir = java.nio.file.Files.createTempDirectory("ConfigDrive");
|
||||||
|
tempDirName = tempDir.toString();
|
||||||
|
|
||||||
|
//create OpenStack files
|
||||||
|
//create folder with empty files
|
||||||
|
File openStackFolder = new File(tempDirName + openStackConfigDriveName);
|
||||||
|
if (openStackFolder.exists() || openStackFolder.mkdirs()) {
|
||||||
|
File vendorDataFile = new File(openStackFolder,"vendor_data.json");
|
||||||
|
try (FileWriter fw = new FileWriter(vendorDataFile); BufferedWriter bw = new BufferedWriter(fw)) {
|
||||||
|
bw.write("{}");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
s_logger.error("Failed to create file ", ex);
|
||||||
|
return new Answer(cmd, ex);
|
||||||
|
}
|
||||||
|
File networkDataFile = new File(openStackFolder, "network_data.json");
|
||||||
|
try (FileWriter fw = new FileWriter(networkDataFile); BufferedWriter bw = new BufferedWriter(fw)) {
|
||||||
|
bw.write("{}");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
s_logger.error("Failed to create file ", ex);
|
||||||
|
return new Answer(cmd, ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_logger.error("Failed to create folder " + openStackFolder);
|
||||||
|
return new Answer(cmd, false, "Failed to create folder " + openStackFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject metaData = new JsonObject();
|
||||||
|
for (String[] item : cmd.getVmData()) {
|
||||||
|
String dataType = item[CONFIGDATA_DIR];
|
||||||
|
String fileName = item[CONFIGDATA_FILE];
|
||||||
|
String content = item[CONFIGDATA_CONTENT];
|
||||||
|
s_logger.debug(String.format("[createConfigDriveIsoForVM] dataType=%s, filename=%s, content=%s",
|
||||||
|
dataType, fileName, (fileName.equals(PASSWORD_FILE)?"********":content)));
|
||||||
|
|
||||||
|
// create file with content in folder
|
||||||
|
if (dataType != null && !dataType.isEmpty()) {
|
||||||
|
//create folder
|
||||||
|
File typeFolder = new File(tempDirName + cloudStackConfigDriveName + dataType);
|
||||||
|
if (typeFolder.exists() || typeFolder.mkdirs()) {
|
||||||
|
if (StringUtils.isNotEmpty(content)) {
|
||||||
|
File file = new File(typeFolder, fileName + ".txt");
|
||||||
|
try (FileWriter fw = new FileWriter(file); BufferedWriter bw = new BufferedWriter(fw)) {
|
||||||
|
bw.write(content);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
s_logger.error("Failed to create file ", ex);
|
||||||
|
return new Answer(cmd, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_logger.error("Failed to create folder " + typeFolder);
|
||||||
|
return new Answer(cmd, false, "Failed to create folder " + typeFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//now write the file to the OpenStack directory
|
||||||
|
metaData = constructOpenStackMetaData(metaData, dataType, fileName, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File metaDataFile = new File(openStackFolder, "meta_data.json");
|
||||||
|
try (FileWriter fw = new FileWriter(metaDataFile); BufferedWriter bw = new BufferedWriter(fw)) {
|
||||||
|
bw.write(metaData.toString());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
s_logger.error("Failed to create file ", ex);
|
||||||
|
return new Answer(cmd, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
String linkResult = linkUserData(tempDirName);
|
||||||
|
if (linkResult != null) {
|
||||||
|
String errMsg = "Unable to create user_data link due to " + linkResult;
|
||||||
|
s_logger.warn(errMsg);
|
||||||
|
return new Answer(cmd, false, errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
File tmpIsoStore = new File(tempDirName, new File(cmd.getIsoFile()).getName());
|
||||||
|
Script command = new Script(!_inSystemVM, "/usr/bin/genisoimage", _timeout, s_logger);
|
||||||
|
command.add("-o", tmpIsoStore.getAbsolutePath());
|
||||||
|
command.add("-ldots");
|
||||||
|
command.add("-allow-lowercase");
|
||||||
|
command.add("-allow-multidot");
|
||||||
|
command.add("-cache-inodes"); // Enable caching inode and device numbers to find hard links to files.
|
||||||
|
command.add("-l");
|
||||||
|
command.add("-quiet");
|
||||||
|
command.add("-J");
|
||||||
|
command.add("-r");
|
||||||
|
command.add("-V", cmd.getConfigDriveLabel());
|
||||||
|
command.add(tempDirName);
|
||||||
|
s_logger.debug("execute command: " + command.toString());
|
||||||
|
String result = command.execute();
|
||||||
|
if (result != null) {
|
||||||
|
String errMsg = "Unable to create iso file: " + cmd.getIsoFile() + " due to " + result;
|
||||||
|
s_logger.warn(errMsg);
|
||||||
|
return new Answer(cmd, false, errMsg);
|
||||||
|
}
|
||||||
|
copyLocalToNfs(tmpIsoStore, new File(cmd.getIsoFile()), cmd.getDestStore());
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
return new Answer(cmd, e);
|
||||||
|
} catch (ConfigurationException e) {
|
||||||
|
s_logger.warn("SecondStorageException ", e);
|
||||||
|
return new Answer(cmd, e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(tempDir.toFile());
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
s_logger.warn("Failed to delete ConfigDrive temporary directory: " + tempDirName, ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Answer(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject constructOpenStackMetaData(JsonObject metaData, String dataType, String fileName, String content) {
|
||||||
|
if (dataType.equals(NetworkModel.METATDATA_DIR) && StringUtils.isNotEmpty(content)) {
|
||||||
|
//keys are a special case in OpenStack format
|
||||||
|
if (NetworkModel.PUBLIC_KEYS_FILE.equals(fileName)) {
|
||||||
|
String[] keyArray = content.replace("\\n", "").split(" ");
|
||||||
|
String keyName = "key";
|
||||||
|
if (keyArray.length > 3 && StringUtils.isNotEmpty(keyArray[2])){
|
||||||
|
keyName = keyArray[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject keyLegacy = new JsonObject();
|
||||||
|
keyLegacy.addProperty("type", "ssh");
|
||||||
|
keyLegacy.addProperty("data", content.replace("\\n", ""));
|
||||||
|
keyLegacy.addProperty("name", keyName);
|
||||||
|
metaData.add("keys", arrayOf(keyLegacy));
|
||||||
|
|
||||||
|
JsonObject key = new JsonObject();
|
||||||
|
key.addProperty(keyName, content);
|
||||||
|
metaData.add("public_keys", key);
|
||||||
|
} else if (NetworkModel.openStackFileMapping.get(fileName) != null) {
|
||||||
|
metaData.addProperty(NetworkModel.openStackFileMapping.get(fileName), content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonArray arrayOf(JsonElement... elements) {
|
||||||
|
JsonArray array = new JsonArray();
|
||||||
|
for (JsonElement element : elements) {
|
||||||
|
array.add(element);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String linkUserData(String tempDirName) {
|
||||||
|
//Hard link the user_data.txt file with the user_data file in the OpenStack directory.
|
||||||
|
String userDataFilePath = tempDirName + cloudStackConfigDriveName + "userdata/user_data.txt";
|
||||||
|
if ((new File(userDataFilePath).exists())) {
|
||||||
|
Script hardLink = new Script(!_inSystemVM, "ln", _timeout, s_logger);
|
||||||
|
hardLink.add(userDataFilePath);
|
||||||
|
hardLink.add(tempDirName + openStackConfigDriveName + "user_data");
|
||||||
|
s_logger.debug("execute command: " + hardLink.toString());
|
||||||
|
return hardLink.execute();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void copyLocalToNfs(File localFile, File isoFile, DataStoreTO destData) throws ConfigurationException, IOException {
|
||||||
|
String scriptsDir = "scripts/storage/secondary";
|
||||||
|
String createVolScr = Script.findScript(scriptsDir, "createvolume.sh");
|
||||||
|
if (createVolScr == null) {
|
||||||
|
throw new ConfigurationException("Unable to find createvolume.sh");
|
||||||
|
}
|
||||||
|
s_logger.info("createvolume.sh found in " + createVolScr);
|
||||||
|
|
||||||
|
int installTimeoutPerGig = 180 * 60 * 1000;
|
||||||
|
int imgSizeGigs = (int) Math.ceil(localFile.length() * 1.0d / (1024 * 1024 * 1024));
|
||||||
|
imgSizeGigs++; // add one just in case
|
||||||
|
long timeout = imgSizeGigs * installTimeoutPerGig;
|
||||||
|
|
||||||
|
Script scr = new Script(createVolScr, timeout, s_logger);
|
||||||
|
scr.add("-s", Integer.toString(imgSizeGigs));
|
||||||
|
scr.add("-n", isoFile.getName());
|
||||||
|
scr.add("-t", getRootDir(destData.getUrl(), _nfsVersion) + "/" + isoFile.getParent());
|
||||||
|
scr.add("-f", localFile.getAbsolutePath());
|
||||||
|
scr.add("-d", "configDrive");
|
||||||
|
String result;
|
||||||
|
result = scr.execute();
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
// script execution failure
|
||||||
|
throw new CloudRuntimeException("Failed to run script " + createVolScr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Answer execute(GetDatadisksCommand cmd) {
|
public Answer execute(GetDatadisksCommand cmd) {
|
||||||
DataTO srcData = cmd.getData();
|
DataTO srcData = cmd.getData();
|
||||||
TemplateObjectTO template = (TemplateObjectTO)srcData;
|
TemplateObjectTO template = (TemplateObjectTO)srcData;
|
||||||
@ -752,7 +1088,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
|||||||
FormatInfo info = processor.process(destPath, null, templateUuid);
|
FormatInfo info = processor.process(destPath, null, templateUuid);
|
||||||
|
|
||||||
TemplateLocation loc = new TemplateLocation(_storage, destPath);
|
TemplateLocation loc = new TemplateLocation(_storage, destPath);
|
||||||
loc.create(destData.getId(), true, templateUuid);
|
loc.create(1, true, templateUuid);
|
||||||
loc.addFormat(info);
|
loc.addFormat(info);
|
||||||
loc.save();
|
loc.save();
|
||||||
TemplateProp prop = loc.getTemplateInfo();
|
TemplateProp prop = loc.getTemplateInfo();
|
||||||
@ -836,7 +1172,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
|||||||
|
|
||||||
FormatInfo info = processor.process(destPath, null, templateName);
|
FormatInfo info = processor.process(destPath, null, templateName);
|
||||||
TemplateLocation loc = new TemplateLocation(_storage, destPath);
|
TemplateLocation loc = new TemplateLocation(_storage, destPath);
|
||||||
loc.create(destData.getId(), true, destData.getName());
|
loc.create(1, true, destData.getName());
|
||||||
loc.addFormat(info);
|
loc.addFormat(info);
|
||||||
loc.save();
|
loc.save();
|
||||||
|
|
||||||
@ -2485,10 +2821,9 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
|||||||
if (_inSystemVM) {
|
if (_inSystemVM) {
|
||||||
_localgw = (String)params.get("localgw");
|
_localgw = (String)params.get("localgw");
|
||||||
if (_localgw != null) { // can only happen inside service vm
|
if (_localgw != null) { // can only happen inside service vm
|
||||||
String mgmtHosts = (String)params.get("host");
|
String mgmtHost = (String)params.get("host");
|
||||||
for (final String mgmtHost : mgmtHosts.split(",")) {
|
|
||||||
addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, mgmtHost);
|
addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, mgmtHost);
|
||||||
}
|
|
||||||
String internalDns1 = (String)params.get("internaldns1");
|
String internalDns1 = (String)params.get("internaldns1");
|
||||||
if (internalDns1 == null) {
|
if (internalDns1 == null) {
|
||||||
s_logger.warn("No DNS entry found during configuration of NfsSecondaryStorage");
|
s_logger.warn("No DNS entry found during configuration of NfsSecondaryStorage");
|
||||||
|
|||||||
@ -31,7 +31,7 @@ public_key=$filepath/metadata/public_keys.txt
|
|||||||
vm_password=$filepath/password/vm_password.txt
|
vm_password=$filepath/password/vm_password.txt
|
||||||
|
|
||||||
# If lable name is other than config, please change the below line as required
|
# If lable name is other than config, please change the below line as required
|
||||||
DefaultDisk=/dev/disk/by-label/config
|
DefaultDisk=/dev/disk/by-label/config-2
|
||||||
|
|
||||||
function usage
|
function usage
|
||||||
{
|
{
|
||||||
|
|||||||
@ -29,7 +29,7 @@ user=root
|
|||||||
mountdir=$(mktemp -d)
|
mountdir=$(mktemp -d)
|
||||||
|
|
||||||
# If lable name is other than config, please change the below line as required
|
# If lable name is other than config, please change the below line as required
|
||||||
DefaultDisk=/dev/disk/by-label/config
|
DefaultDisk=/dev/disk/by-label/config-2
|
||||||
|
|
||||||
|
|
||||||
Password_File=$mountdir/cloudstack/password/vm_password.txt
|
Password_File=$mountdir/cloudstack/password/vm_password.txt
|
||||||
|
|||||||
@ -29,7 +29,7 @@ user=root
|
|||||||
mountdir=$(mktemp -d)
|
mountdir=$(mktemp -d)
|
||||||
|
|
||||||
# If lable name is other than config, please change the below line as required
|
# If lable name is other than config, please change the below line as required
|
||||||
DefaultDisk=/dev/disk/by-label/config
|
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
|
keys_received=0
|
||||||
|
|||||||
@ -25,7 +25,7 @@ echo Const HKEY_CURRENT_USER = ^&H80000001
|
|||||||
echo registryKeyPath = "SOFTWARE\CLOUDSTACKmd5Checksum\" >> %PasswordReset_Script%
|
echo registryKeyPath = "SOFTWARE\CLOUDSTACKmd5Checksum\" >> %PasswordReset_Script%
|
||||||
echo registryKeyName = "PasswordMd5Checksum" >> %PasswordReset_Script%
|
echo registryKeyName = "PasswordMd5Checksum" >> %PasswordReset_Script%
|
||||||
echo CDPath = "" >> %PasswordReset_Script%
|
echo CDPath = "" >> %PasswordReset_Script%
|
||||||
echo configLabelName = "config" >> %PasswordReset_Script%
|
echo configLabelName = "config-2" >> %PasswordReset_Script%
|
||||||
echo. >> %PasswordReset_Script%
|
echo. >> %PasswordReset_Script%
|
||||||
echo. >> %PasswordReset_Script%
|
echo. >> %PasswordReset_Script%
|
||||||
echo. >> %PasswordReset_Script%
|
echo. >> %PasswordReset_Script%
|
||||||
|
|||||||
1947
test/integration/component/test_configdrive.py
Normal file
1947
test/integration/component/test_configdrive.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -198,7 +198,7 @@ class TestDeployVMs(cloudstackTestCase):
|
|||||||
Returns mount path if config drive is attached else False
|
Returns mount path if config drive is attached else False
|
||||||
"""
|
"""
|
||||||
mountdir = "/root/iso"
|
mountdir = "/root/iso"
|
||||||
cmd = "blkid -t LABEL='config' /dev/hd? /dev/sd? /dev/xvd? -o device"
|
cmd = "blkid -t LABEL='config-2' /dev/sr? /dev/hd? /dev/sd? /dev/xvd? -o device"
|
||||||
try:
|
try:
|
||||||
self.debug("SSH into VM: %s" % vm_ip)
|
self.debug("SSH into VM: %s" % vm_ip)
|
||||||
ssh = self.vm.get_ssh_client(ipaddress=vm_ip, reconnect=True)
|
ssh = self.vm.get_ssh_client(ipaddress=vm_ip, reconnect=True)
|
||||||
@ -261,7 +261,7 @@ class TestDeployVMs(cloudstackTestCase):
|
|||||||
|
|
||||||
def verifySshKey(self, vm_ip, iso_path):
|
def verifySshKey(self, vm_ip, iso_path):
|
||||||
|
|
||||||
publicKey_file = iso_path+"/cloudstack/metadata/public_keys.txt"
|
publicKey_file = iso_path+"/cloudstack/metadata/public-keys.txt"
|
||||||
try:
|
try:
|
||||||
self.debug("SSH into VM: %s" % vm_ip)
|
self.debug("SSH into VM: %s" % vm_ip)
|
||||||
ssh = self.vm.get_ssh_client(ipaddress=vm_ip)
|
ssh = self.vm.get_ssh_client(ipaddress=vm_ip)
|
||||||
@ -285,7 +285,7 @@ class TestDeployVMs(cloudstackTestCase):
|
|||||||
response = {}
|
response = {}
|
||||||
self.debug("SSH into VM: %s" % vm_ip)
|
self.debug("SSH into VM: %s" % vm_ip)
|
||||||
ssh = self.vm.get_ssh_client(ipaddress=vm_ip, reconnect=True)
|
ssh = self.vm.get_ssh_client(ipaddress=vm_ip, reconnect=True)
|
||||||
vm_files = ["availability_zone.txt", "instance_id.txt", "service_offering.txt", "vm_id.txt"]
|
vm_files = ["availability-zone.txt", "instance-id.txt", "service-offering.txt", "vm-id.txt"]
|
||||||
for file in vm_files:
|
for file in vm_files:
|
||||||
cmd = "cat %s" % metadata_dir+file
|
cmd = "cat %s" % metadata_dir+file
|
||||||
res = ssh.execute(cmd)
|
res = ssh.execute(cmd)
|
||||||
@ -296,22 +296,22 @@ class TestDeployVMs(cloudstackTestCase):
|
|||||||
|
|
||||||
def verifyMetaData(self, metadata):
|
def verifyMetaData(self, metadata):
|
||||||
|
|
||||||
metadata_files = ["availability_zone.txt", "instance_id.txt", "service_offering.txt", "vm_id.txt"]
|
metadata_files = ["availability-zone.txt", "instance-id.txt", "service-offering.txt", "vm-id.txt"]
|
||||||
for mfile in metadata_files:
|
for mfile in metadata_files:
|
||||||
if mfile not in metadata:
|
if mfile not in metadata:
|
||||||
self.fail("{} file is not found in vm metadata".format(mfile))
|
self.fail("{} file is not found in vm metadata".format(mfile))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(metadata["availability_zone.txt"][0]),
|
str(metadata["availability-zone.txt"][0]),
|
||||||
self.zone.name,
|
self.zone.name,
|
||||||
"Zone name inside metadata does not match with the zone"
|
"Zone name inside metadata does not match with the zone"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(metadata["instance_id.txt"][0]),
|
str(metadata["instance-id.txt"][0]),
|
||||||
self.vm.instancename,
|
self.vm.instancename,
|
||||||
"vm name inside metadata does not match with the instance name"
|
"vm name inside metadata does not match with the instance name"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(metadata["service_offering.txt"][0]),
|
str(metadata["service-offering.txt"][0]),
|
||||||
self.vm.serviceofferingname,
|
self.vm.serviceofferingname,
|
||||||
"Service offering inside metadata does not match with the instance offering"
|
"Service offering inside metadata does not match with the instance offering"
|
||||||
)
|
)
|
||||||
@ -320,7 +320,7 @@ class TestDeployVMs(cloudstackTestCase):
|
|||||||
self.vm.instancename)
|
self.vm.instancename)
|
||||||
self.assertEqual(validateList(qresultset)[0], PASS, "sql query returned invalid response")
|
self.assertEqual(validateList(qresultset)[0], PASS, "sql query returned invalid response")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
metadata["vm_id.txt"][0],
|
metadata["vm-id.txt"][0],
|
||||||
unicode(qresultset[0][0]),
|
unicode(qresultset[0][0]),
|
||||||
"vm id in metadata does not match with the vm id from cloud db"
|
"vm id in metadata does not match with the vm id from cloud db"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -44,6 +44,8 @@ from marvin.lib.common import (get_domain,
|
|||||||
get_template,
|
get_template,
|
||||||
get_zone)
|
get_zone)
|
||||||
from marvin.cloudstackAPI import (restartVPC,
|
from marvin.cloudstackAPI import (restartVPC,
|
||||||
|
enableNuageUnderlayVlanIpRange,
|
||||||
|
disableNuageUnderlayVlanIpRange,
|
||||||
listNuageUnderlayVlanIpRanges)
|
listNuageUnderlayVlanIpRanges)
|
||||||
# Import System Modules
|
# Import System Modules
|
||||||
from retry import retry
|
from retry import retry
|
||||||
@ -320,6 +322,31 @@ class nuageTestCase(cloudstackTestCase):
|
|||||||
self.debug("Cleanup complete!")
|
self.debug("Cleanup complete!")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# enable_NuageUnderlayPublicIpRange - Enables/configures underlay
|
||||||
|
# networking for the given public IP range in Nuage VSP
|
||||||
|
def enable_NuageUnderlayPublicIpRange(self, vlanid):
|
||||||
|
cmd = enableNuageUnderlayVlanIpRange. \
|
||||||
|
enableNuageUnderlayVlanIpRangeCmd()
|
||||||
|
cmd.id = vlanid
|
||||||
|
self.api_client.enableNuageUnderlayVlanIpRange(cmd)
|
||||||
|
|
||||||
|
# disable_NuageUnderlayPublicIpRange - Disables/de-configures underlay
|
||||||
|
# networking for the given public IP range in Nuage VSP
|
||||||
|
def disable_NuageUnderlayPublicIpRange(self, public_ip_range):
|
||||||
|
cmd = disableNuageUnderlayVlanIpRange. \
|
||||||
|
disableNuageUnderlayVlanIpRangeCmd()
|
||||||
|
cmd.id = public_ip_range.vlan.id
|
||||||
|
self.api_client.enableNuageUnderlayVlanIpRange(cmd)
|
||||||
|
|
||||||
|
# list_NuageUnderlayPublicIpRanges - Lists underlay networking
|
||||||
|
# enabled/configured public IP ranges in Nuage VSP
|
||||||
|
def list_NuageUnderlayPublicIpRanges(self, public_ip_range=None):
|
||||||
|
cmd = listNuageUnderlayVlanIpRanges.listNuageUnderlayVlanIpRangesCmd()
|
||||||
|
if public_ip_range:
|
||||||
|
cmd.id = public_ip_range.vlan.id
|
||||||
|
cmd.underlay = True
|
||||||
|
return self.api_client.listNuageUnderlayVlanIpRanges(cmd)
|
||||||
|
|
||||||
# create_VpcOffering - Creates VPC offering
|
# create_VpcOffering - Creates VPC offering
|
||||||
@needscleanup
|
@needscleanup
|
||||||
def create_VpcOffering(cls, vpc_offering, suffix=None):
|
def create_VpcOffering(cls, vpc_offering, suffix=None):
|
||||||
@ -395,6 +422,7 @@ class nuageTestCase(cloudstackTestCase):
|
|||||||
testdata = cls.test_data["network"]
|
testdata = cls.test_data["network"]
|
||||||
testdata["name"] = "TestNet-" + gateway + "-" + str(nw_off.name)
|
testdata["name"] = "TestNet-" + gateway + "-" + str(nw_off.name)
|
||||||
testdata["displaytext"] = "Test Network"
|
testdata["displaytext"] = "Test Network"
|
||||||
|
testdata["gateway"] = gateway
|
||||||
testdata["netmask"] = netmask
|
testdata["netmask"] = netmask
|
||||||
network = Network.create(cls.api_client,
|
network = Network.create(cls.api_client,
|
||||||
testdata,
|
testdata,
|
||||||
@ -402,7 +430,6 @@ class nuageTestCase(cloudstackTestCase):
|
|||||||
domainid=account.domainid,
|
domainid=account.domainid,
|
||||||
networkofferingid=nw_off.id,
|
networkofferingid=nw_off.id,
|
||||||
zoneid=cls.zone.id,
|
zoneid=cls.zone.id,
|
||||||
gateway=gateway,
|
|
||||||
vlan=vlan,
|
vlan=vlan,
|
||||||
externalid=externalid,
|
externalid=externalid,
|
||||||
vpcid=vpc.id if vpc else cls.vpc.id
|
vpcid=vpc.id if vpc else cls.vpc.id
|
||||||
@ -435,7 +462,7 @@ class nuageTestCase(cloudstackTestCase):
|
|||||||
# create_VM - Creates VM in the given network(s)
|
# create_VM - Creates VM in the given network(s)
|
||||||
@needscleanup
|
@needscleanup
|
||||||
def create_VM(cls, network_list, host_id=None, start_vm=True,
|
def create_VM(cls, network_list, host_id=None, start_vm=True,
|
||||||
testdata=None, account=None):
|
testdata=None, account=None, keypair=None):
|
||||||
network_ids = []
|
network_ids = []
|
||||||
if isinstance(network_list, list):
|
if isinstance(network_list, list):
|
||||||
for network in network_list:
|
for network in network_list:
|
||||||
@ -457,7 +484,8 @@ class nuageTestCase(cloudstackTestCase):
|
|||||||
zoneid=cls.zone.id,
|
zoneid=cls.zone.id,
|
||||||
networkids=network_ids,
|
networkids=network_ids,
|
||||||
startvm=start_vm,
|
startvm=start_vm,
|
||||||
hostid=host_id
|
hostid=host_id,
|
||||||
|
keypair=keypair
|
||||||
)
|
)
|
||||||
cls.debug("Created VM with ID - %s in network(s) with ID(s) - %s"
|
cls.debug("Created VM with ID - %s in network(s) with ID(s) - %s"
|
||||||
% (vm.id, network_ids))
|
% (vm.id, network_ids))
|
||||||
@ -490,22 +518,22 @@ class nuageTestCase(cloudstackTestCase):
|
|||||||
def migrate_VM(self, vm):
|
def migrate_VM(self, vm):
|
||||||
self.debug("Checking if a host is available for migration...")
|
self.debug("Checking if a host is available for migration...")
|
||||||
hosts = Host.listForMigration(self.api_client, virtualmachineid=vm.id)
|
hosts = Host.listForMigration(self.api_client, virtualmachineid=vm.id)
|
||||||
|
if hosts:
|
||||||
self.assertEqual(isinstance(hosts, list), True,
|
self.assertEqual(isinstance(hosts, list), True,
|
||||||
"List hosts should return a valid list"
|
"List hosts should return a valid list"
|
||||||
)
|
)
|
||||||
# Remove the host of current VM from the hosts list
|
|
||||||
vm_info = VirtualMachine.list(self.api_client, id=vm.id)[0]
|
|
||||||
hosts[:] = [host for host in hosts if host.id != vm_info.hostid]
|
|
||||||
if len(hosts) <= 0:
|
|
||||||
self.skipTest("No host available for migration. "
|
|
||||||
"Test requires at-least 2 hosts")
|
|
||||||
host = hosts[0]
|
host = hosts[0]
|
||||||
self.debug("Migrating VM with ID: %s to Host: %s" % (vm.id, host.id))
|
self.debug("Migrating VM with ID: "
|
||||||
|
"%s to Host: %s" % (vm.id, host.id))
|
||||||
try:
|
try:
|
||||||
vm.migrate(self.api_client, hostid=host.id)
|
vm.migrate(self.api_client, hostid=host.id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.fail("Failed to migrate instance, %s" % e)
|
self.fail("Failed to migrate instance, %s" % e)
|
||||||
self.debug("Migrated VM with ID: %s to Host: %s" % (vm.id, host.id))
|
self.debug("Migrated VM with ID: "
|
||||||
|
"%s to Host: %s" % (vm.id, host.id))
|
||||||
|
else:
|
||||||
|
self.debug("No host available for migration. "
|
||||||
|
"Test requires at-least 2 hosts")
|
||||||
|
|
||||||
# delete_VM - Deletes the given VM
|
# delete_VM - Deletes the given VM
|
||||||
def delete_VM(self, vm, expunge=True):
|
def delete_VM(self, vm, expunge=True):
|
||||||
|
|||||||
2278
test/integration/plugins/nuagevsp/test_nuage_configdrive.py
Normal file
2278
test/integration/plugins/nuagevsp/test_nuage_configdrive.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -23,9 +23,7 @@ from marvin.lib.base import (Account,
|
|||||||
PublicIpRange,
|
PublicIpRange,
|
||||||
Network,
|
Network,
|
||||||
VirtualMachine)
|
VirtualMachine)
|
||||||
from marvin.cloudstackAPI import (enableNuageUnderlayVlanIpRange,
|
from marvin.lib.common import list_virtual_machines
|
||||||
disableNuageUnderlayVlanIpRange,
|
|
||||||
listNuageUnderlayVlanIpRanges)
|
|
||||||
from marvin.lib.common import list_virtual_machines
|
from marvin.lib.common import list_virtual_machines
|
||||||
|
|
||||||
# Import System Modules
|
# Import System Modules
|
||||||
@ -54,31 +52,6 @@ class TestNuageStaticNat(nuageTestCase):
|
|||||||
self.cleanup = [self.account]
|
self.cleanup = [self.account]
|
||||||
return
|
return
|
||||||
|
|
||||||
# enable_NuageUnderlayPublicIpRange - Enables/configures underlay
|
|
||||||
# networking for the given public IP range in Nuage VSP
|
|
||||||
def enable_NuageUnderlayPublicIpRange(self, public_ip_range):
|
|
||||||
cmd = enableNuageUnderlayVlanIpRange.\
|
|
||||||
enableNuageUnderlayVlanIpRangeCmd()
|
|
||||||
cmd.id = public_ip_range.vlan.id
|
|
||||||
self.api_client.enableNuageUnderlayVlanIpRange(cmd)
|
|
||||||
|
|
||||||
# disable_NuageUnderlayPublicIpRange - Disables/de-configures underlay
|
|
||||||
# networking for the given public IP range in Nuage VSP
|
|
||||||
def disable_NuageUnderlayPublicIpRange(self, public_ip_range):
|
|
||||||
cmd = disableNuageUnderlayVlanIpRange.\
|
|
||||||
disableNuageUnderlayVlanIpRangeCmd()
|
|
||||||
cmd.id = public_ip_range.vlan.id
|
|
||||||
self.api_client.enableNuageUnderlayVlanIpRange(cmd)
|
|
||||||
|
|
||||||
# list_NuageUnderlayPublicIpRanges - Lists underlay networking
|
|
||||||
# enabled/configured public IP ranges in Nuage VSP
|
|
||||||
def list_NuageUnderlayPublicIpRanges(self, public_ip_range=None):
|
|
||||||
cmd = listNuageUnderlayVlanIpRanges.listNuageUnderlayVlanIpRangesCmd()
|
|
||||||
if public_ip_range:
|
|
||||||
cmd.id = public_ip_range.vlan.id
|
|
||||||
cmd.underlay = True
|
|
||||||
return self.api_client.listNuageUnderlayVlanIpRanges(cmd)
|
|
||||||
|
|
||||||
# create_PublicIpRange - Creates public IP range
|
# create_PublicIpRange - Creates public IP range
|
||||||
def create_PublicIpRange(self):
|
def create_PublicIpRange(self):
|
||||||
self.debug("Creating public IP range")
|
self.debug("Creating public IP range")
|
||||||
@ -115,20 +88,21 @@ class TestNuageStaticNat(nuageTestCase):
|
|||||||
# validate_NuageUnderlayPublicIpRange - Validates Nuage underlay enabled
|
# validate_NuageUnderlayPublicIpRange - Validates Nuage underlay enabled
|
||||||
# public IP range creation and state
|
# public IP range creation and state
|
||||||
def validate_NuageUnderlayPublicIpRange(self, public_ip_range):
|
def validate_NuageUnderlayPublicIpRange(self, public_ip_range):
|
||||||
nuage_underlay_public_ip_ranges = \
|
self.nuage_underlay_public_ip_ranges = \
|
||||||
self.list_NuageUnderlayPublicIpRanges(public_ip_range)
|
self.list_NuageUnderlayPublicIpRanges(public_ip_range)
|
||||||
self.assertEqual(isinstance(nuage_underlay_public_ip_ranges, list),
|
self.assertEqual(isinstance(self.nuage_underlay_public_ip_ranges,
|
||||||
|
list),
|
||||||
True,
|
True,
|
||||||
"List Nuage Underlay Public IP Range should return "
|
"List Nuage Underlay Public IP Range should return "
|
||||||
"a valid list"
|
"a valid list"
|
||||||
)
|
)
|
||||||
self.assertEqual(public_ip_range.vlan.startip,
|
self.assertEqual(public_ip_range.vlan.startip,
|
||||||
nuage_underlay_public_ip_ranges[0].startip,
|
self.nuage_underlay_public_ip_ranges[0].startip,
|
||||||
"Start IP of the public IP range should match with "
|
"Start IP of the public IP range should match with "
|
||||||
"the returned list data"
|
"the returned list data"
|
||||||
)
|
)
|
||||||
self.assertEqual(public_ip_range.vlan.endip,
|
self.assertEqual(public_ip_range.vlan.endip,
|
||||||
nuage_underlay_public_ip_ranges[0].endip,
|
self.nuage_underlay_public_ip_ranges[0].endip,
|
||||||
"End IP of the public IP range should match with the "
|
"End IP of the public IP range should match with the "
|
||||||
"returned list data"
|
"returned list data"
|
||||||
)
|
)
|
||||||
@ -358,7 +332,7 @@ class TestNuageStaticNat(nuageTestCase):
|
|||||||
|
|
||||||
self.debug("Enabling Nuage underlay capability (underlay networking) "
|
self.debug("Enabling Nuage underlay capability (underlay networking) "
|
||||||
"for the created public IP range...")
|
"for the created public IP range...")
|
||||||
self.enable_NuageUnderlayPublicIpRange(public_ip_range)
|
self.enable_NuageUnderlayPublicIpRange(public_ip_range.vlan.id)
|
||||||
self.validate_NuageUnderlayPublicIpRange(public_ip_range)
|
self.validate_NuageUnderlayPublicIpRange(public_ip_range)
|
||||||
self.debug("Nuage underlay capability (underlay networking) for the "
|
self.debug("Nuage underlay capability (underlay networking) for the "
|
||||||
"created public IP range is successfully enabled")
|
"created public IP range is successfully enabled")
|
||||||
@ -532,6 +506,7 @@ class TestNuageStaticNat(nuageTestCase):
|
|||||||
self.debug("Acquired public IP in the created Isolated network "
|
self.debug("Acquired public IP in the created Isolated network "
|
||||||
"successfully released in CloudStack")
|
"successfully released in CloudStack")
|
||||||
self.delete_VM(vm_1)
|
self.delete_VM(vm_1)
|
||||||
|
|
||||||
# Bug CLOUDSTACK-9398
|
# Bug CLOUDSTACK-9398
|
||||||
"""
|
"""
|
||||||
self.debug("Creating a persistent Isolated network with Static NAT "
|
self.debug("Creating a persistent Isolated network with Static NAT "
|
||||||
|
|||||||
@ -49,6 +49,27 @@ test_data = {
|
|||||||
"forvirtualnetwork": "true",
|
"forvirtualnetwork": "true",
|
||||||
"vlan": "300"
|
"vlan": "300"
|
||||||
},
|
},
|
||||||
|
"publiciprange1": {
|
||||||
|
"gateway": "10.200.100.1",
|
||||||
|
"netmask": "255.255.255.0",
|
||||||
|
"startip": "10.200.100.101",
|
||||||
|
"endip": "10.200.100.105",
|
||||||
|
"forvirtualnetwork": "false"
|
||||||
|
},
|
||||||
|
"publiciprange2": {
|
||||||
|
"gateway": "10.219.1.1",
|
||||||
|
"netmask": "255.255.255.0",
|
||||||
|
"startip": "10.219.1.2",
|
||||||
|
"endip": "10.219.1.5",
|
||||||
|
"forvirtualnetwork": "false"
|
||||||
|
},
|
||||||
|
"publiciprange3": {
|
||||||
|
"gateway": "10.200.100.1",
|
||||||
|
"netmask": "255.255.255.0",
|
||||||
|
"startip": "10.200.100.2",
|
||||||
|
"endip": "10.200.100.20",
|
||||||
|
"forvirtualnetwork": "false"
|
||||||
|
},
|
||||||
"private_gateway": {
|
"private_gateway": {
|
||||||
"ipaddress": "172.16.1.2",
|
"ipaddress": "172.16.1.2",
|
||||||
"gateway": "172.16.1.1",
|
"gateway": "172.16.1.1",
|
||||||
@ -473,6 +494,20 @@ test_data = {
|
|||||||
"SecurityGroup": "SecurityGroupProvider"
|
"SecurityGroup": "SecurityGroupProvider"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"shared_network_config_drive_offering": {
|
||||||
|
"name": 'shared_network_config_drive_offering',
|
||||||
|
"displaytext": 'shared_network_config_drive_offering',
|
||||||
|
"guestiptype": 'shared',
|
||||||
|
"supportedservices": 'Dhcp,UserData',
|
||||||
|
"traffictype": 'GUEST',
|
||||||
|
"specifyVlan": "True",
|
||||||
|
"specifyIpRanges": "True",
|
||||||
|
"availability": 'Optional',
|
||||||
|
"serviceProviderList": {
|
||||||
|
"Dhcp": "VirtualRouter",
|
||||||
|
"UserData": 'ConfigDrive'
|
||||||
|
}
|
||||||
|
},
|
||||||
"shared_network_sg": {
|
"shared_network_sg": {
|
||||||
"name": "Shared-Network-SG-Test",
|
"name": "Shared-Network-SG-Test",
|
||||||
"displaytext": "Shared-Network_SG-Test",
|
"displaytext": "Shared-Network_SG-Test",
|
||||||
@ -2277,10 +2312,10 @@ test_data = {
|
|||||||
"network_all": {
|
"network_all": {
|
||||||
"name": "SharedNetwork-All-nuage",
|
"name": "SharedNetwork-All-nuage",
|
||||||
"displaytext": "SharedNetwork-All-nuage",
|
"displaytext": "SharedNetwork-All-nuage",
|
||||||
"gateway": "10.223.1.1",
|
"gateway": "10.200.100.1",
|
||||||
"netmask": "255.255.255.0",
|
"netmask": "255.255.255.0",
|
||||||
"startip": "10.223.1.21",
|
"startip": "10.200.100.21",
|
||||||
"endip": "10.223.1.100",
|
"endip": "10.200.100.100",
|
||||||
"acltype": "Domain"
|
"acltype": "Domain"
|
||||||
},
|
},
|
||||||
"network_domain_with_no_subdomain_access": {
|
"network_domain_with_no_subdomain_access": {
|
||||||
@ -2313,10 +2348,10 @@ test_data = {
|
|||||||
"acltype": "Account"
|
"acltype": "Account"
|
||||||
},
|
},
|
||||||
"publiciprange1": {
|
"publiciprange1": {
|
||||||
"gateway": "10.223.1.1",
|
"gateway": "10.200.100.1",
|
||||||
"netmask": "255.255.255.0",
|
"netmask": "255.255.255.0",
|
||||||
"startip": "10.223.1.101",
|
"startip": "10.200.100.101",
|
||||||
"endip": "10.223.1.105",
|
"endip": "10.200.100.105",
|
||||||
"forvirtualnetwork": "false"
|
"forvirtualnetwork": "false"
|
||||||
},
|
},
|
||||||
"publiciprange2": {
|
"publiciprange2": {
|
||||||
@ -2327,10 +2362,10 @@ test_data = {
|
|||||||
"forvirtualnetwork": "false"
|
"forvirtualnetwork": "false"
|
||||||
},
|
},
|
||||||
"publiciprange3": {
|
"publiciprange3": {
|
||||||
"gateway": "10.223.1.1",
|
"gateway": "10.200.100.1",
|
||||||
"netmask": "255.255.255.0",
|
"netmask": "255.255.255.0",
|
||||||
"startip": "10.223.1.2",
|
"startip": "10.200.100.2",
|
||||||
"endip": "10.223.1.20",
|
"endip": "10.200.100.20",
|
||||||
"forvirtualnetwork": "false"
|
"forvirtualnetwork": "false"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2422,7 +2422,7 @@
|
|||||||
//p.s. Netscaler is supported in both vpc and non-vpc
|
//p.s. Netscaler is supported in both vpc and non-vpc
|
||||||
if ($useVpc.is(':visible') && $useVpcCb.is(':checked')) { //*** vpc ***
|
if ($useVpc.is(':visible') && $useVpcCb.is(':checked')) { //*** vpc ***
|
||||||
$optionsOfProviders.each(function(index) {
|
$optionsOfProviders.each(function(index) {
|
||||||
if ($(this).val() == 'InternalLbVm' || $(this).val() == 'VpcVirtualRouter' || $(this).val() == 'Netscaler' || $(this).val() == 'NuageVsp' || $(this).val() == 'NuageVspVpc' || $(this).val() == 'BigSwitchBcf') {
|
if ($(this).val() == 'InternalLbVm' || $(this).val() == 'VpcVirtualRouter' || $(this).val() == 'Netscaler' || $(this).val() == 'NuageVsp' || $(this).val() == 'NuageVspVpc' || $(this).val() == 'BigSwitchBcf' || $(this).val() == 'ConfigDrive') {
|
||||||
$(this).attr('disabled', false);
|
$(this).attr('disabled', false);
|
||||||
} else {
|
} else {
|
||||||
$(this).attr('disabled', true);
|
$(this).attr('disabled', true);
|
||||||
|
|||||||
@ -7640,6 +7640,120 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ConfigDrive: {
|
||||||
|
id: "ConfigDrive",
|
||||||
|
label: "ConfigDrive",
|
||||||
|
isMaximized: true,
|
||||||
|
type: 'detailView',
|
||||||
|
fields: {
|
||||||
|
name: {
|
||||||
|
label: 'label.name'
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
label: 'label.status',
|
||||||
|
indicator: {
|
||||||
|
'Enabled': 'on'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tabs: {
|
||||||
|
network: {
|
||||||
|
title: 'label.network',
|
||||||
|
fields: [{
|
||||||
|
name: {
|
||||||
|
label: 'label.name'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
state: {
|
||||||
|
label: 'label.state'
|
||||||
|
},
|
||||||
|
supportedServices: {
|
||||||
|
label: 'label.supported.services'
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
label: 'label.id'
|
||||||
|
},
|
||||||
|
physicalnetworkid: {
|
||||||
|
label: 'label.physical.network.ID'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
dataProvider: function(args) {
|
||||||
|
refreshNspData("ConfigDrive");
|
||||||
|
args.response.success({
|
||||||
|
actionFilter: ovsProviderActionFilter,
|
||||||
|
data: $.extend(nspMap["ConfigDrive"], {
|
||||||
|
supportedServices: nspMap["ConfigDrive"] == undefined? "": nspMap["ConfigDrive"].servicelist.join(', ')
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
enable: {
|
||||||
|
label: 'label.enable.provider',
|
||||||
|
action: function(args) {
|
||||||
|
$.ajax({
|
||||||
|
url: createURL("updateNetworkServiceProvider&id=" + nspMap["ConfigDrive"].id + "&state=Enabled"),
|
||||||
|
dataType: "json",
|
||||||
|
success: function(json) {
|
||||||
|
var jid = json.updatenetworkserviceproviderresponse.jobid;
|
||||||
|
args.response.success({
|
||||||
|
_custom: {
|
||||||
|
jobId: jid,
|
||||||
|
getUpdatedItem: function(json) {
|
||||||
|
$(window).trigger('cloudStack.fullRefresh');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
confirm: function(args) {
|
||||||
|
return 'message.confirm.enable.provider';
|
||||||
|
},
|
||||||
|
notification: function() {
|
||||||
|
return 'label.enable.provider';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: {
|
||||||
|
poll: pollAsyncJobResult
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disable: {
|
||||||
|
label: 'label.disable.provider',
|
||||||
|
action: function(args) {
|
||||||
|
$.ajax({
|
||||||
|
url: createURL("updateNetworkServiceProvider&id=" + nspMap["ConfigDrive"].id + "&state=Disabled"),
|
||||||
|
dataType: "json",
|
||||||
|
success: function(json) {
|
||||||
|
var jid = json.updatenetworkserviceproviderresponse.jobid;
|
||||||
|
args.response.success({
|
||||||
|
_custom: {
|
||||||
|
jobId: jid,
|
||||||
|
getUpdatedItem: function(json) {
|
||||||
|
$(window).trigger('cloudStack.fullRefresh');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
confirm: function(args) {
|
||||||
|
return 'message.confirm.disable.provider';
|
||||||
|
},
|
||||||
|
notification: function() {
|
||||||
|
return 'label.disable.provider';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: {
|
||||||
|
poll: pollAsyncJobResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22190,6 +22304,9 @@
|
|||||||
case "GloboDns":
|
case "GloboDns":
|
||||||
nspMap["GloboDns"] = items[i];
|
nspMap["GloboDns"] = items[i];
|
||||||
break;
|
break;
|
||||||
|
case "ConfigDrive":
|
||||||
|
nspMap["ConfigDrive"] = items[i];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22287,6 +22404,11 @@
|
|||||||
name: 'GloboDNS',
|
name: 'GloboDNS',
|
||||||
state: nspMap.GloboDns ? nspMap.GloboDns.state : 'Disabled'
|
state: nspMap.GloboDns ? nspMap.GloboDns.state : 'Disabled'
|
||||||
});
|
});
|
||||||
|
nspHardcodingArray.push({
|
||||||
|
id: "ConfigDrive",
|
||||||
|
name: "ConfigDrive",
|
||||||
|
state: nspMap.ConfigDrive ? nspMap.ConfigDrive.state : 'Disabled'
|
||||||
|
});
|
||||||
|
|
||||||
//CLOUDSTACK-6840: OVS refers to SDN provider. However, we are not supporting SDN in this release.
|
//CLOUDSTACK-6840: OVS refers to SDN provider. However, we are not supporting SDN in this release.
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -116,6 +116,10 @@ import com.cloud.utils.script.Script;
|
|||||||
public class VirtualMachineMO extends BaseMO {
|
public class VirtualMachineMO extends BaseMO {
|
||||||
private static final Logger s_logger = Logger.getLogger(VirtualMachineMO.class);
|
private static final Logger s_logger = Logger.getLogger(VirtualMachineMO.class);
|
||||||
private static final ExecutorService MonitorServiceExecutor = Executors.newCachedThreadPool(new NamedThreadFactory("VM-Question-Monitor"));
|
private static final ExecutorService MonitorServiceExecutor = Executors.newCachedThreadPool(new NamedThreadFactory("VM-Question-Monitor"));
|
||||||
|
|
||||||
|
public static final String ANSWER_YES = "0";
|
||||||
|
public static final String ANSWER_NO = "1";
|
||||||
|
|
||||||
private ManagedObjectReference _vmEnvironmentBrowser = null;
|
private ManagedObjectReference _vmEnvironmentBrowser = null;
|
||||||
|
|
||||||
public VirtualMachineMO(VmwareContext context, ManagedObjectReference morVm) {
|
public VirtualMachineMO(VmwareContext context, ManagedObjectReference morVm) {
|
||||||
@ -1402,6 +1406,12 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
|
|
||||||
// isoDatastorePath: [datastore name] isoFilePath
|
// isoDatastorePath: [datastore name] isoFilePath
|
||||||
public void attachIso(String isoDatastorePath, ManagedObjectReference morDs, boolean connect, boolean connectAtBoot) throws Exception {
|
public void attachIso(String isoDatastorePath, ManagedObjectReference morDs, boolean connect, boolean connectAtBoot) throws Exception {
|
||||||
|
attachIso(isoDatastorePath, morDs, connect, connectAtBoot, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// isoDatastorePath: [datastore name] isoFilePath
|
||||||
|
public void attachIso(String isoDatastorePath, ManagedObjectReference morDs,
|
||||||
|
boolean connect, boolean connectAtBoot, Integer key) throws Exception {
|
||||||
|
|
||||||
if (s_logger.isTraceEnabled())
|
if (s_logger.isTraceEnabled())
|
||||||
s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath + ", datastore: " +
|
s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath + ", datastore: " +
|
||||||
@ -1411,7 +1421,12 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
assert (morDs != null);
|
assert (morDs != null);
|
||||||
|
|
||||||
boolean newCdRom = false;
|
boolean newCdRom = false;
|
||||||
VirtualCdrom cdRom = (VirtualCdrom)getIsoDevice();
|
VirtualCdrom cdRom;
|
||||||
|
if (key == null) {
|
||||||
|
cdRom = (VirtualCdrom) getIsoDevice();
|
||||||
|
} else {
|
||||||
|
cdRom = (VirtualCdrom) getIsoDevice(key);
|
||||||
|
}
|
||||||
if (cdRom == null) {
|
if (cdRom == null) {
|
||||||
newCdRom = true;
|
newCdRom = true;
|
||||||
cdRom = new VirtualCdrom();
|
cdRom = new VirtualCdrom();
|
||||||
@ -1461,11 +1476,15 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
s_logger.trace("vCenter API trace - detachIso() done(successfully)");
|
s_logger.trace("vCenter API trace - detachIso() done(successfully)");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void detachIso(String isoDatastorePath) throws Exception {
|
public int detachIso(String isoDatastorePath) throws Exception {
|
||||||
|
return detachIso(isoDatastorePath, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int detachIso(String isoDatastorePath, final boolean force) throws Exception {
|
||||||
if (s_logger.isTraceEnabled())
|
if (s_logger.isTraceEnabled())
|
||||||
s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath);
|
s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath);
|
||||||
|
|
||||||
VirtualDevice device = getIsoDevice();
|
VirtualDevice device = getIsoDevice(isoDatastorePath);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
if (s_logger.isTraceEnabled())
|
if (s_logger.isTraceEnabled())
|
||||||
s_logger.trace("vCenter API trace - detachIso() done(failed)");
|
s_logger.trace("vCenter API trace - detachIso() done(failed)");
|
||||||
@ -1514,7 +1533,7 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) {
|
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) {
|
||||||
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + msg.getId() +
|
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + msg.getId() +
|
||||||
", for safe operation we will automatically decline it");
|
", for safe operation we will automatically decline it");
|
||||||
vmMo.answerVM(question.getId(), "1");
|
vmMo.answerVM(question.getId(), force ? ANSWER_YES : ANSWER_NO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1531,7 +1550,7 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) {
|
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) {
|
||||||
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + question.getId() +
|
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + question.getId() +
|
||||||
". Message id : " + msgId + ". Message text : " + msgText + ", for safe operation we will automatically decline it.");
|
". Message id : " + msgId + ". Message text : " + msgText + ", for safe operation we will automatically decline it.");
|
||||||
vmMo.answerVM(question.getId(), "1");
|
vmMo.answerVM(question.getId(), force ? ANSWER_YES : ANSWER_NO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1570,6 +1589,7 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
flags[0] = true;
|
flags[0] = true;
|
||||||
future.cancel(true);
|
future.cancel(true);
|
||||||
}
|
}
|
||||||
|
return device.getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<VmdkFileDescriptor, byte[]> getVmdkFileInfo(String vmdkDatastorePath) throws Exception {
|
public Pair<VmdkFileDescriptor, byte[]> getVmdkFileInfo(String vmdkDatastorePath) throws Exception {
|
||||||
@ -2826,6 +2846,32 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VirtualDevice getIsoDevice(int key) throws Exception {
|
||||||
|
List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device");
|
||||||
|
if (devices != null && devices.size() > 0) {
|
||||||
|
for (VirtualDevice device : devices) {
|
||||||
|
if (device instanceof VirtualCdrom && device.getKey() == key) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualDevice getIsoDevice(String filename) throws Exception {
|
||||||
|
List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient().
|
||||||
|
getDynamicProperty(_mor, "config.hardware.device");
|
||||||
|
if(devices != null && devices.size() > 0) {
|
||||||
|
for(VirtualDevice device : devices) {
|
||||||
|
if(device instanceof VirtualCdrom && device.getBacking() instanceof VirtualCdromIsoBackingInfo &&
|
||||||
|
((VirtualCdromIsoBackingInfo)device.getBacking()).getFileName().equals(filename)) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public int getNextDeviceNumber(int controllerKey) throws Exception {
|
public int getNextDeviceNumber(int controllerKey) throws Exception {
|
||||||
List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device");
|
List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device");
|
||||||
|
|
||||||
@ -2982,7 +3028,7 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) {
|
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) {
|
||||||
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + msg.getId() +
|
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + msg.getId() +
|
||||||
", for safe operation we will automatically decline it");
|
", for safe operation we will automatically decline it");
|
||||||
vmMo.answerVM(question.getId(), "1");
|
vmMo.answerVM(question.getId(), ANSWER_NO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2999,7 +3045,7 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) {
|
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) {
|
||||||
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + question.getId() +
|
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + question.getId() +
|
||||||
". Message id : " + msgId + ". Message text : " + msgText + ", for safe operation we will automatically decline it.");
|
". Message id : " + msgId + ". Message text : " + msgText + ", for safe operation we will automatically decline it.");
|
||||||
vmMo.answerVM(question.getId(), "1");
|
vmMo.answerVM(question.getId(), ANSWER_NO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user