mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
it works
This commit is contained in:
parent
c94b6acadf
commit
9d2916ffcc
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
build/replace.properties
|
||||
build/build.number
|
||||
bin/
|
||||
cloudstack-proprietary/
|
||||
|
||||
@ -77,8 +77,7 @@ import com.cloud.utils.script.Script;
|
||||
*
|
||||
**/
|
||||
public class Agent implements HandlerFactory, IAgentControl {
|
||||
private static final Logger s_logger = Logger.getLogger(Agent.class.getName());
|
||||
|
||||
private static final Logger s_logger = Logger.getLogger(Agent.class.getName());
|
||||
public enum ExitStatus {
|
||||
Normal(0), // Normal status = 0.
|
||||
Upgrade(65), // Exiting for upgrade.
|
||||
|
||||
41
api/src/com/cloud/network/ovs/OvsCreateGreTunnelAnswer.java
Normal file
41
api/src/com/cloud/network/ovs/OvsCreateGreTunnelAnswer.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
|
||||
public class OvsCreateGreTunnelAnswer extends Answer {
|
||||
String hostIp;
|
||||
String remoteIp;
|
||||
String bridge;
|
||||
String key;
|
||||
|
||||
public OvsCreateGreTunnelAnswer(Command cmd, boolean success, String details) {
|
||||
super(cmd, success, details);
|
||||
}
|
||||
|
||||
public OvsCreateGreTunnelAnswer(Command cmd, boolean success,
|
||||
String details, String hostIp, String remoteIp, String bridge,
|
||||
String key) {
|
||||
super(cmd, success, details);
|
||||
this.hostIp = hostIp;
|
||||
this.remoteIp = remoteIp;
|
||||
this.bridge = bridge;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getHostIp() {
|
||||
return hostIp;
|
||||
}
|
||||
|
||||
public String getRemoteIp() {
|
||||
return remoteIp;
|
||||
}
|
||||
|
||||
public String getBridge() {
|
||||
return bridge;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
20
api/src/com/cloud/network/ovs/OvsDeleteFlowCommand.java
Normal file
20
api/src/com/cloud/network/ovs/OvsDeleteFlowCommand.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.api.Command;
|
||||
|
||||
public class OvsDeleteFlowCommand extends Command {
|
||||
String vmName;
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
public OvsDeleteFlowCommand(String vmName) {
|
||||
this.vmName = vmName;
|
||||
}
|
||||
}
|
||||
24
api/src/com/cloud/network/ovs/OvsSetTagAndFlowAnswer.java
Normal file
24
api/src/com/cloud/network/ovs/OvsSetTagAndFlowAnswer.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
|
||||
public class OvsSetTagAndFlowAnswer extends Answer {
|
||||
Long vmId;
|
||||
Long seqno;
|
||||
|
||||
public OvsSetTagAndFlowAnswer(Command cmd, boolean success, String details) {
|
||||
super(cmd, success, details);
|
||||
OvsSetTagAndFlowCommand c = (OvsSetTagAndFlowCommand)cmd;
|
||||
this.vmId = c.getVmId();
|
||||
this.seqno = Long.parseLong(c.getSeqNo());
|
||||
}
|
||||
|
||||
public Long getVmId() {
|
||||
return vmId;
|
||||
}
|
||||
|
||||
public Long getSeqNo() {
|
||||
return seqno;
|
||||
}
|
||||
}
|
||||
@ -5,12 +5,18 @@ import com.cloud.agent.api.Command;
|
||||
public class OvsSetTagAndFlowCommand extends Command {
|
||||
String vlans;
|
||||
String vmName;
|
||||
String seqno;
|
||||
Long vmId;
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getSeqNo() {
|
||||
return seqno;
|
||||
}
|
||||
|
||||
public String getVlans() {
|
||||
return vlans;
|
||||
}
|
||||
@ -19,8 +25,14 @@ public class OvsSetTagAndFlowCommand extends Command {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
public OvsSetTagAndFlowCommand(String vmName, String vlans) {
|
||||
public Long getVmId() {
|
||||
return vmId;
|
||||
}
|
||||
|
||||
public OvsSetTagAndFlowCommand(String vmName, String vlans, String seqno, Long vmId) {
|
||||
this.vmName = vmName;
|
||||
this.vlans = vlans;
|
||||
this.seqno = seqno;
|
||||
this.vmId = vmId;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,3 +6,4 @@ DBHOST=localhost
|
||||
AGENTLOGDIR=logs
|
||||
AGENTLOG=logs/agent.log
|
||||
MSMNTDIR=/mnt
|
||||
DBROOTPW=
|
||||
|
||||
26
core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java
Normal file
26
core/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.vm.State;
|
||||
|
||||
public class PingRoutingWithOvsCommand extends PingRoutingCommand {
|
||||
List<Pair<String, Long>> states;
|
||||
|
||||
protected PingRoutingWithOvsCommand() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PingRoutingWithOvsCommand(Host.Type type, long id,
|
||||
Map<String, State> states, List<Pair<String, Long>> ovsStates) {
|
||||
super(type, id, states);
|
||||
this.states = ovsStates;
|
||||
}
|
||||
|
||||
public List<Pair<String, Long>> getStates() {
|
||||
return states;
|
||||
}
|
||||
}
|
||||
@ -94,6 +94,7 @@ import com.cloud.agent.api.ModifyStoragePoolCommand;
|
||||
import com.cloud.agent.api.PingCommand;
|
||||
import com.cloud.agent.api.PingRoutingCommand;
|
||||
import com.cloud.agent.api.PingRoutingWithNwGroupsCommand;
|
||||
import com.cloud.agent.api.PingRoutingWithOvsCommand;
|
||||
import com.cloud.agent.api.PingTestCommand;
|
||||
import com.cloud.agent.api.PoolEjectCommand;
|
||||
import com.cloud.agent.api.PrepareForMigrationAnswer;
|
||||
@ -159,7 +160,10 @@ import com.cloud.network.Networks;
|
||||
import com.cloud.network.Networks.BroadcastDomainType;
|
||||
import com.cloud.network.Networks.IsolationType;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.ovs.OvsCreateGreTunnelAnswer;
|
||||
import com.cloud.network.ovs.OvsCreateGreTunnelCommand;
|
||||
import com.cloud.network.ovs.OvsDeleteFlowCommand;
|
||||
import com.cloud.network.ovs.OvsSetTagAndFlowAnswer;
|
||||
import com.cloud.network.ovs.OvsSetTagAndFlowCommand;
|
||||
import com.cloud.resource.ServerResource;
|
||||
import com.cloud.storage.Storage;
|
||||
@ -247,6 +251,7 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
|
||||
protected StorageLayer _storage;
|
||||
protected boolean _canBridgeFirewall = false;
|
||||
protected boolean _isOvs = false;
|
||||
protected HashMap<StoragePoolType, StoragePoolResource> _pools = new HashMap<StoragePoolType, StoragePoolResource>(5);
|
||||
|
||||
public enum SRType {
|
||||
@ -449,6 +454,8 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
return execute((OvsCreateGreTunnelCommand)cmd);
|
||||
} else if (cmd instanceof OvsSetTagAndFlowCommand) {
|
||||
return execute((OvsSetTagAndFlowCommand)cmd);
|
||||
} else if (cmd instanceof OvsDeleteFlowCommand) {
|
||||
return execute((OvsDeleteFlowCommand)cmd);
|
||||
} else {
|
||||
return Answer.createUnsupportedCommandAnswer(cmd);
|
||||
}
|
||||
@ -3312,9 +3319,12 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
if (newStates == null) {
|
||||
newStates = new HashMap<String, State>();
|
||||
}
|
||||
if (!_canBridgeFirewall) {
|
||||
if (!_canBridgeFirewall && !_isOvs) {
|
||||
return new PingRoutingCommand(getType(), id, newStates);
|
||||
} else {
|
||||
} else if (_isOvs) {
|
||||
List<Pair<String, Long>>ovsStates = ovsFullSyncStates();
|
||||
return new PingRoutingWithOvsCommand(getType(), id, newStates, ovsStates);
|
||||
}else {
|
||||
HashMap<String, Pair<Long, Long>> nwGrpStates = syncNetworkGroups(conn, id);
|
||||
return new PingRoutingWithNwGroupsCommand(getType(), id, newStates, nwGrpStates);
|
||||
}
|
||||
@ -3820,7 +3830,61 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
return Boolean.valueOf(callHostPlugin(conn, "vmops", "can_bridge_firewall", "host_uuid", _host.uuid));
|
||||
}
|
||||
|
||||
private Answer execute(OvsSetTagAndFlowCommand cmd) {
|
||||
private Answer execute(OvsDeleteFlowCommand cmd) {
|
||||
_isOvs = true;
|
||||
|
||||
Connection conn = getConnection();
|
||||
try {
|
||||
String nwName = Networks.BroadcastScheme.VSwitch.toString();
|
||||
Network nw = getNetworkByName(conn, nwName);
|
||||
assert nw!= null : "Why there is no vswith network ???";
|
||||
String bridge = nw.getBridge(conn);
|
||||
String result = callHostPlugin(conn, "vmops", "ovs_delete_flow", "bridge", bridge,
|
||||
"vmName", cmd.getVmName());
|
||||
|
||||
if (result.equalsIgnoreCase("SUCCESS")) {
|
||||
return new Answer(cmd, true, "success to delete flows for " + cmd.getVmName());
|
||||
} else {
|
||||
return new Answer(cmd, false, result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new Answer(cmd, false, "failed to delete flow for " + cmd.getVmName());
|
||||
}
|
||||
|
||||
private List<Pair<String, Long>> ovsFullSyncStates() {
|
||||
Connection conn = getConnection();
|
||||
try {
|
||||
String result = callHostPlugin(conn, "vmops", "ovs_get_vm_log", "host_uuid", _host.uuid);
|
||||
String [] logs = result != null ?result.split(";"): new String [0];
|
||||
List<Pair<String, Long>> states = new ArrayList<Pair<String, Long>>();
|
||||
for (String log: logs){
|
||||
String [] info = log.split(",");
|
||||
if (info.length != 4) {
|
||||
s_logger.warn("Wrong element number in ovs log");
|
||||
continue;
|
||||
}
|
||||
|
||||
//','.join([bridge, vmName, vmId, seqno])
|
||||
try {
|
||||
states.add(new Pair<String,Long>(info[0], Long.parseLong(info[3])));
|
||||
} catch (NumberFormatException nfe) {
|
||||
states.add(new Pair<String,Long>(info[0], -1L));
|
||||
}
|
||||
}
|
||||
|
||||
return states;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private OvsSetTagAndFlowAnswer execute(OvsSetTagAndFlowCommand cmd) {
|
||||
_isOvs = true;
|
||||
|
||||
Connection conn = getConnection();
|
||||
try {
|
||||
String nwName = Networks.BroadcastScheme.VSwitch.toString();
|
||||
@ -3833,48 +3897,47 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
* plugin side
|
||||
*/
|
||||
String result = callHostPlugin(conn, "vmops", "ovs_set_tag_and_flow", "bridge", bridge,
|
||||
"vmName", cmd.getVmName(), "vlans", cmd.getVlans());
|
||||
"vmName", cmd.getVmName(), "vlans", cmd.getVlans(), "seqno", cmd.getSeqNo());
|
||||
s_logger.debug("set flow for " + cmd.getVmName() + " " + result);
|
||||
|
||||
if (result.equalsIgnoreCase("SUCCESS")) {
|
||||
return new Answer(cmd, true, "Set flow for " + cmd.getVmName()
|
||||
+ " success, vlans:" + cmd.getVlans());
|
||||
return new OvsSetTagAndFlowAnswer(cmd, true, result);
|
||||
} else {
|
||||
return new Answer(cmd, false, "Set flow for " + cmd.getVmName()
|
||||
+ " failed, vlans:" + cmd.getVlans());
|
||||
return new OvsSetTagAndFlowAnswer(cmd, false, result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new Answer(cmd, false, "Set flow for " + cmd.getVmName()
|
||||
+ " failed, vlans:" + cmd.getVlans());
|
||||
return new OvsSetTagAndFlowAnswer(cmd, false, "EXCEPTION");
|
||||
}
|
||||
|
||||
private Answer execute(OvsCreateGreTunnelCommand cmd) {
|
||||
|
||||
private OvsCreateGreTunnelAnswer execute(OvsCreateGreTunnelCommand cmd) {
|
||||
_isOvs = true;
|
||||
|
||||
Connection conn = getConnection();
|
||||
String bridge = "unkonwn";
|
||||
try {
|
||||
String nwName = Networks.BroadcastScheme.VSwitch.toString();
|
||||
Network nw = getNetworkByName(conn, nwName);
|
||||
if (nw == null) {
|
||||
nw = setupvSwitchNetwork(conn);
|
||||
}
|
||||
//TODO: we may store vswtich network to _host
|
||||
Network nw = setupvSwitchNetwork(conn);
|
||||
bridge = nw.getBridge(conn);
|
||||
|
||||
String result = callHostPlugin(conn, "vmops", "vlanRemapUtils",
|
||||
"op", "createGRE", "bridge", nw.getBridge(conn),
|
||||
"op", "createGRE", "bridge", bridge,
|
||||
"remoteIP", cmd.getRemoteIp(), "greKey", cmd.getKey());
|
||||
if (result.equalsIgnoreCase("SUCCESS")) {
|
||||
return new Answer(cmd, true, "create gre tunnel to "
|
||||
+ cmd.getRemoteIp() + " success");
|
||||
if (result.equalsIgnoreCase("SUCCESS") || result.equalsIgnoreCase("TUNNEL_EXISTED")) {
|
||||
return new OvsCreateGreTunnelAnswer(cmd, true, result);
|
||||
} else {
|
||||
return new Answer(cmd, false, "create gre tunnel to "
|
||||
+ cmd.getRemoteIp() + " failed");
|
||||
return new OvsCreateGreTunnelAnswer(cmd, false, result,
|
||||
_host.ip, cmd.getRemoteIp(), bridge, cmd.getKey());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new Answer(cmd, false, "create gre tunnel to " + cmd.getRemoteIp() + " failed");
|
||||
return new OvsCreateGreTunnelAnswer(cmd, false, "EXCEPTION", _host.ip,
|
||||
cmd.getRemoteIp(), bridge, cmd.getKey());
|
||||
}
|
||||
|
||||
private Answer execute(SecurityIngressRulesCmd cmd) {
|
||||
|
||||
@ -29,6 +29,9 @@ errors = \
|
||||
"SWITCH_NOT_RUN" : "SWITCH_NOT_RUN", \
|
||||
"NO_VSCTL" : "NO_VSCTL", \
|
||||
"COMMAND_FAILED" : "COMMAND_FAILED", \
|
||||
"TUNNEL_EXISTED" : "TUNNEL_EXISTED", \
|
||||
"NO_INPORT" : "NO_INPORT", \
|
||||
"NO_OFPORT" : "NO_OFPORT", \
|
||||
|
||||
"ERR_ARGS_NUM" : "ERR_ARGS_NUM", \
|
||||
"ERROR_OP" : "ERROR_OP", \
|
||||
@ -137,24 +140,24 @@ def isUUID (uuid):
|
||||
|
||||
return 0
|
||||
|
||||
#FIXME: better check method
|
||||
def checkGREInterface (bridge, remoteIP, greKey):
|
||||
listIfaces = [vsctlPath, "list interface"]
|
||||
res = doCmd (listIfaces, True)
|
||||
ports = getPortsOnBridge(bridge)
|
||||
if ports == None:
|
||||
return 0
|
||||
|
||||
start = False
|
||||
num = 0
|
||||
keyStr = "key=%s" % greKey
|
||||
uuid = ''
|
||||
for i in res:
|
||||
if "_uuid" in i:
|
||||
(x, uuid) = i.split(":")
|
||||
uuid = strip(uuid)
|
||||
for i in ports:
|
||||
ifaces = getInterfacesOnPort(i)
|
||||
if ifaces == None:
|
||||
continue
|
||||
|
||||
if "options" in i and remoteIP in i and keyStr in i:
|
||||
log("WARNING: GRE tunnel for remote_ip=%s key=%s already here" % \
|
||||
(remoteIP, greKey))
|
||||
return -1
|
||||
for j in ifaces:
|
||||
if j == '[]':
|
||||
continue
|
||||
options = getFieldOfInterface(j, "options")
|
||||
if remoteIP in options and greKey in options:
|
||||
log("WARNING: GRE tunnel for remote_ip=%s key=%s already here, \
|
||||
interface(%s)" % (remoteIP, greKey, j))
|
||||
return -1
|
||||
|
||||
return 0
|
||||
|
||||
@ -164,8 +167,17 @@ def createGRE (bridge, remoteIP, greKey):
|
||||
|
||||
name = "%sgre" % bridge
|
||||
if checkGREInterface(bridge, remoteIP, greKey) < 0:
|
||||
result = errors["TUNNEL_EXISTED"]
|
||||
return 0
|
||||
|
||||
wait = [vsctlPath, "--timeout=30 wait-until bridge %s -- get bridge %s name" % \
|
||||
(bridge, bridge)]
|
||||
res = doCmd(wait)
|
||||
if bridge not in res:
|
||||
log("WARNIING:Can't find bridge %s for creating tunnel!" % bridge)
|
||||
result = errors["COMMAND_FAILED"]
|
||||
return -1
|
||||
|
||||
createInterface = [vsctlPath, "create interface", "name=%s" % name, \
|
||||
'type=gre options:"remote_ip=%s key=%s"' % (remoteIP, greKey)]
|
||||
ifaceUUID = doCmd (createInterface)
|
||||
@ -180,9 +192,18 @@ def createGRE (bridge, remoteIP, greKey):
|
||||
result = errors["COMMAND_FAILED"];
|
||||
return -1
|
||||
|
||||
addBridge = [vsctlPath, "add bridge %s" % bridge, "port %s" % portUUID]
|
||||
addBridge = [vsctlPath, "add bridge %s" % bridge, "ports %s" % portUUID]
|
||||
doCmd (addBridge)
|
||||
return 0
|
||||
|
||||
wait = [vsctlPath, "--timeout=5 wait-until port %s -- get port %s name" % \
|
||||
(name, name)]
|
||||
res = doCmd(wait)
|
||||
if name in res:
|
||||
result = errors["SUCCESS"]
|
||||
return 0
|
||||
else:
|
||||
result = errors["COMMAND_FAILED"]
|
||||
return -1
|
||||
######################## End GRE creation utils ##########################
|
||||
|
||||
######################## Flow creation utils ##########################
|
||||
@ -263,7 +284,7 @@ def getOfPortsByType(bridge, askGre):
|
||||
portUuids = getPortsOnBridge(bridge)
|
||||
if portUuids == None:
|
||||
log("WARNING:No ports on bridge %s" % bridge)
|
||||
return -1
|
||||
return []
|
||||
|
||||
OfPorts = []
|
||||
for i in portUuids:
|
||||
@ -293,28 +314,14 @@ def getNoneGreOfPort(bridge):
|
||||
def getGreOfPorts(bridge):
|
||||
return getOfPortsByType(bridge, True)
|
||||
|
||||
def findInPort():
|
||||
listIface = [vsctlPath, "list interface"]
|
||||
res = doCmd (listIface, True)
|
||||
|
||||
inport = []
|
||||
port = ""
|
||||
for i in res:
|
||||
if "ofport" in i:
|
||||
(x, port) = i.split(":")
|
||||
port = port.lstrip().rstrip()
|
||||
|
||||
if "type" in i:
|
||||
(x, type) = i.split(":")
|
||||
type = type.lstrip().rstrip()
|
||||
if type == "gre":
|
||||
inport.append (port)
|
||||
return inport
|
||||
|
||||
|
||||
def formatFlow(inPort, vlan, mac, outPut):
|
||||
flow = "in_port=%s dl_vlan=%s dl_dst=%s idle_timeout=0 hard_timeout=0 \
|
||||
actions=strip_vlan,output:%s" % (inPort, vlan, mac, outPut)
|
||||
priority=10000 actions=strip_vlan,output:%s" % (inPort, vlan, mac, outPut)
|
||||
return flow
|
||||
|
||||
def formatDropFlow(inPort, vlan):
|
||||
flow = "in_port=%s dl_vlan=%s priority=0 idle_timeout=0 hard_timeout=0 \
|
||||
actions=drop" % (inPort, vlan)
|
||||
return flow
|
||||
|
||||
def delFlow(mac):
|
||||
@ -327,6 +334,21 @@ def delARPFlow(vlan):
|
||||
delFlow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
|
||||
doCmd(delFlow)
|
||||
|
||||
def delDHCPFlow(vlan):
|
||||
param = "dl_type=0x0800 nw_proto=6 tp_src=547 dl_vlan=%s" % vlan
|
||||
delFlow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
|
||||
doCmd(delFlow)
|
||||
|
||||
def formatDHCPFlow(bridge, inPort, vlan, ports):
|
||||
outputs = ''
|
||||
for i in ports:
|
||||
str = "output:%s," % i
|
||||
outputs += str
|
||||
outputs = outputs[:-1]
|
||||
flow = "in_port=%s dl_vlan=%s dl_type=0x0800 nw_proto=6 tp_src=547 idle_timeout=0 hard_timeout=0 \
|
||||
priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs)
|
||||
return flow
|
||||
|
||||
def formatARPFlow(bridge, inPort, vlan, ports):
|
||||
outputs = ''
|
||||
for i in ports:
|
||||
@ -335,21 +357,25 @@ def formatARPFlow(bridge, inPort, vlan, ports):
|
||||
|
||||
outputs = outputs[:-1]
|
||||
flow = "in_port=%s dl_vlan=%s dl_type=0x0806 idle_timeout=0 hard_timeout=0 \
|
||||
actions=strip_vlan,%s" % (inPort, vlan, outputs)
|
||||
priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs)
|
||||
return flow
|
||||
|
||||
def createFlow (bridge, vifName, mac, remap):
|
||||
global result
|
||||
inport = getGreOfPorts(bridge)
|
||||
if len(inport) == 0:
|
||||
log("WARNING: no inport found")
|
||||
result = errors["NO_INPORT"]
|
||||
return -1
|
||||
|
||||
output = getVifPort(bridge, vifName)
|
||||
if output == None:
|
||||
log("WARNING: cannot find ofport for %s" % vifName)
|
||||
result = errors["NO_OFPORT"]
|
||||
return -1
|
||||
if output == '[]':
|
||||
log("WARNING: ofport is [] for %s" % vifName)
|
||||
result = errors["NO_OFPORT"]
|
||||
return -1
|
||||
|
||||
#del old flow here, if any, but in normal there should be no old flow
|
||||
@ -363,23 +389,36 @@ def createFlow (bridge, vifName, mac, remap):
|
||||
noneGreOfPorts = getNoneGreOfPort(bridge)
|
||||
isARP = True
|
||||
if len(noneGreOfPorts) == 0:
|
||||
log("WARNING: no none GRE ofports found, no ARP flow will be created")
|
||||
log("WARNING: no none GRE ofports found, no ARP flow and DHCP flow will be created")
|
||||
isARP = False
|
||||
|
||||
for j in remap.split("/"):
|
||||
delARPFlow(j)
|
||||
delDHCPFlow(j)
|
||||
for i in inport:
|
||||
flow = formatDropFlow(i, j)
|
||||
param = bridge + ' "%s"' % flow
|
||||
dropflow = ["ovs-ofctl add-flow", param]
|
||||
doCmd (dropflow)
|
||||
|
||||
flow = formatFlow(i, j, mac, output)
|
||||
param = bridge + ' "%s"' % flow
|
||||
addflow = ["ovs-ofctl add-flow", param]
|
||||
doCmd (addflow)
|
||||
|
||||
|
||||
if isARP == True:
|
||||
flow = formatARPFlow(bridge, i, j, noneGreOfPorts)
|
||||
param = bridge + ' "%s"' % flow
|
||||
addflow = ["ovs-ofctl add-flow", param]
|
||||
doCmd (addflow)
|
||||
|
||||
flow = formatDHCPFlow(bridge, i, j, noneGreOfPorts)
|
||||
param = bridge + ' "%s"' % flow
|
||||
addflow = ["ovs-ofctl add-flow", param]
|
||||
doCmd (addflow)
|
||||
|
||||
result = errors["SUCCESS"]
|
||||
return 0
|
||||
######################## End Flow creation utils ##########################
|
||||
|
||||
@ -402,20 +441,24 @@ def setTag(bridge, vifName, vlan):
|
||||
return 0
|
||||
|
||||
def doCreateGRE(bridge, remoteIP, key):
|
||||
global result
|
||||
if createGRE(bridge, remoteIP, key) < 0:
|
||||
log("WARNING: create GRE tunnel on %s for %s failed" % (bridge, \
|
||||
log("create GRE tunnel on %s for %s failed" % (bridge, \
|
||||
remoteIP))
|
||||
else:
|
||||
log("WARNING: create GRE tunnel on %s for %s success" % (bridge, \
|
||||
remoteIP))
|
||||
print result
|
||||
|
||||
def doCreateFlow (bridge, vifName, mac, remap):
|
||||
global result
|
||||
if createFlow(bridge, vifName, mac, remap) < 0:
|
||||
log ("Create flow failed(bridge=%s, vifName=%s, mac=%s,\
|
||||
remap=%s" % (bridge, vifName, mac, remap))
|
||||
else:
|
||||
log ("Create flow success(bridge=%s, vifName=%s, mac=%s,\
|
||||
remap=%s" % (bridge, vifName, mac, remap))
|
||||
print result
|
||||
|
||||
def doSetTag (bridge, vifName, tag):
|
||||
setTag(bridge, vifName, tag)
|
||||
@ -469,6 +512,7 @@ if __name__ == "__main__":
|
||||
remoteIP = sys.argv[3]
|
||||
key = sys.argv[4]
|
||||
doCreateGRE(bridge, remoteIP, key)
|
||||
sys.exit(0)
|
||||
elif op == "createFlow":
|
||||
checkArgNum(6)
|
||||
bridge = sys.argv[2]
|
||||
@ -476,6 +520,7 @@ if __name__ == "__main__":
|
||||
mac = sys.argv[4]
|
||||
remap = sys.argv[5]
|
||||
doCreateFlow(bridge, vifName, mac, remap)
|
||||
sys.exit(0)
|
||||
elif op == "deleteFlow":
|
||||
checkArgNum(6)
|
||||
bridge = sys.argv[2]
|
||||
|
||||
@ -553,19 +553,187 @@ def default_ebtables_rules(vm_name, vif, vm_ip, vm_mac):
|
||||
except:
|
||||
util.SMlog("Failed to program default ebtables OUT rules")
|
||||
return 'false'
|
||||
|
||||
def ovs_set_tag_and_flow(session, args):
|
||||
def get_vif_field(name, field):
|
||||
return session.xenapi.VIF.get_record(name).get(field)
|
||||
|
||||
def format_ovs_vm_log_name(vmName):
|
||||
vm_name = "ovs-%s" % vmName;
|
||||
logfilename = "/var/run/cloud/" + vm_name +".log"
|
||||
return logfilename
|
||||
|
||||
def remove_ovs_log_for_vm(vmName):
|
||||
logfilename = format_ovs_vm_log_name(vmName)
|
||||
|
||||
result = True
|
||||
try:
|
||||
os.remove(logfilename)
|
||||
except:
|
||||
util.SMlog("Failed to delete ovs log file " + logfilename)
|
||||
result = False
|
||||
return result
|
||||
|
||||
def ovs_get_info_from_log(vmName, num):
|
||||
logfilename = format_ovs_vm_log_name(vmName)
|
||||
try:
|
||||
lines = [line.rstrip() for line in open(logfilename)]
|
||||
return lines[num]
|
||||
except:
|
||||
util.SMlog("Failed to open ovs log %s" % logfilename);
|
||||
remove_ovs_log_for_vm(vmName)
|
||||
return None
|
||||
|
||||
def ovs_get_common_info_from_log(vmName):
|
||||
return ovs_get_info_from_log(vmName, 0)
|
||||
|
||||
def ovs_get_nic_info_from_log(vmName):
|
||||
return ovs_get_info_from_log(vmName, 1)
|
||||
|
||||
def ovs_get_mac_info_from_log(vmName):
|
||||
return ovs_get_info_from_log(vmName, 2)
|
||||
|
||||
def ovs_get_vlans_info_from_log(vmName):
|
||||
return ovs_get_info_from_log(vmName, 3)
|
||||
|
||||
def ovs_parse_common_info_from_log(vmName, num):
|
||||
info = ovs_get_common_info_from_log(vmName)
|
||||
if info == None:
|
||||
return None
|
||||
return info.split(",")[num]
|
||||
|
||||
def ovs_get_bridge_from_log(vmName):
|
||||
return ovs_parse_common_info_from_log(vmName, 1)
|
||||
|
||||
def ovs_get_vm_id_from_log(vmName):
|
||||
return ovs_parse_common_info_from_log(vmName, 2)
|
||||
|
||||
def ovs_get_seqno_from_log(vmName):
|
||||
return ovs_parse_common_info_from_log(vmName, 3)
|
||||
|
||||
def ovs_handle_rebooted_vm(session, vmName):
|
||||
curr_domid = '-1'
|
||||
|
||||
(curr_domid, vifrs, hostuuid) = ovs_get_domid_vifrs_hostuuid(session, vmName)
|
||||
|
||||
old_id = ovs_get_vm_id_from_log(vmName)
|
||||
if curr_domid == old_id:
|
||||
util.SMlog("OvsInfo:%s is normal" % vmName)
|
||||
return True
|
||||
|
||||
util.SMlog("%s rebooted, reset flow for it" % vmName)
|
||||
try:
|
||||
vlans = ovs_get_vlans_info_from_log(vmName)
|
||||
bridge = ovs_get_bridge_from_log(vmName)
|
||||
except Exception, e:
|
||||
util.SMlog(e.__str__())
|
||||
util.SMlog("ovs get info from %s failed" % \
|
||||
format_ovs_vm_log_name(vmName))
|
||||
return False
|
||||
|
||||
i = 0
|
||||
if vlans == None:
|
||||
util.SMlog("OVSErr: cannot get vlans for %s" % vmName)
|
||||
return False
|
||||
|
||||
tag = vlans.split('/')[0]
|
||||
nics = []
|
||||
macs = []
|
||||
for vifr in vifrs:
|
||||
vifName = "vif" + curr_domid + "." + vifr[0]
|
||||
vlanRemapUtils(session, {"op":"setTag", "vifName":vifName, "bridge":bridge, "tag":tag})
|
||||
vlanRemapUtils(session, {"op":"createFlow", "vifName":vifName, "bridge":bridge, "mac":vifr[1], "remap":vlans})
|
||||
nics.append(vifName)
|
||||
macs.append(vifr[1])
|
||||
i += 1
|
||||
seqno = ovs_get_seqno_from_log(vmName)
|
||||
ovs_write_vm_log(bridge, vmName, curr_domid, seqno, nics, macs, vlans)
|
||||
|
||||
#see if there is rebooted vm to handle
|
||||
ovs_get_vm_log(session, {"host_uuid":hostuuid})
|
||||
return True
|
||||
|
||||
@echo
|
||||
def ovs_get_vm_log(session, args):
|
||||
host_uuid = args.pop('host_uuid')
|
||||
try:
|
||||
session = get_xapi_session()
|
||||
|
||||
thishost = session.xenapi.host.get_by_uuid(host_uuid)
|
||||
hostrec = session.xenapi.host.get_record(thishost)
|
||||
vms = hostrec.get('resident_VMs')
|
||||
except:
|
||||
util.SMlog("Failed to get host from uuid " + host_uuid)
|
||||
return ' '
|
||||
|
||||
result = []
|
||||
try:
|
||||
for name in [session.xenapi.VM.get_name_label(x) for x in vms]:
|
||||
if 1 not in [ name.startswith(c) for c in ['r-', 'i-'] ]:
|
||||
continue
|
||||
ovs_handle_rebooted_vm(session, name)
|
||||
if name.startswith('i-'):
|
||||
info = ovs_get_common_info_from_log(name)
|
||||
result.append(info)
|
||||
except Exception, e:
|
||||
util.SMlog(e.__str__())
|
||||
util.SMlog("OVs failed to get rule logs, better luck next time!")
|
||||
|
||||
return ";".join(result)
|
||||
|
||||
def ovs_write_vm_log(bridge, vmName, vmId, seqno, vifNames, macs, vlans):
|
||||
logfilename = format_ovs_vm_log_name(vmName)
|
||||
|
||||
util.SMlog("Writing ovs log to " + logfilename)
|
||||
logf = open(logfilename, 'w')
|
||||
output = ','.join([vmName, bridge, vmId, seqno])
|
||||
result = True
|
||||
try:
|
||||
logf.write(output)
|
||||
logf.write('\n')
|
||||
output = ','.join(vifNames)
|
||||
logf.write(output)
|
||||
logf.write('\n')
|
||||
output = ','.join(macs)
|
||||
logf.write(output)
|
||||
logf.write('\n')
|
||||
logf.write(vlans)
|
||||
logf.write('\n')
|
||||
except:
|
||||
util.SMlog("Failed to write to ovs log file " + logfilename)
|
||||
result = False
|
||||
|
||||
logf.close()
|
||||
|
||||
return result
|
||||
|
||||
def ovs_delete_flow(session, args):
|
||||
bridge = args.pop('bridge')
|
||||
vm_name = args.pop('vmName')
|
||||
vlanStr = args.pop('vlans')
|
||||
|
||||
nicStr = ovs_get_nic_info_from_log(vm_name)
|
||||
macStr = ovs_get_mac_info_from_log(vm_name)
|
||||
vlanStr = ovs_get_vlans_info_from_log(vm_name)
|
||||
|
||||
if nicStr == None or macStr == None or vlanStr == None:
|
||||
return 'ERROR_LOG'
|
||||
|
||||
nics = nicStr.split(',')
|
||||
macs = macStr.split(',')
|
||||
if len(nics) != len(macs):
|
||||
return 'ERROR_LOG'
|
||||
|
||||
i = 0
|
||||
for nic in nics:
|
||||
vlanRemapUtils(session, {"op":"deleteFlow", "bridge":bridge, \
|
||||
"vifName":nic, "mac":macs[i], "remap":vlanStr})
|
||||
i += 1
|
||||
return 'SUCCESS'
|
||||
|
||||
def ovs_get_domid_vifrs_hostuuid(session, vm_name):
|
||||
def get_vif_field(name, field):
|
||||
return session.xenapi.VIF.get_record(name).get(field)
|
||||
|
||||
try:
|
||||
vm = session.xenapi.VM.get_by_name_label(vm_name)
|
||||
if len(vm) != 1:
|
||||
return 'false'
|
||||
return 'NO_VM'
|
||||
vm_rec = session.xenapi.VM.get_record(vm[0])
|
||||
vm_vifs = vm_rec.get('VIFs')
|
||||
vifrs = []
|
||||
@ -573,13 +741,27 @@ def ovs_set_tag_and_flow(session, args):
|
||||
rec = (get_vif_field(vif, 'device'), get_vif_field(vif, 'MAC'))
|
||||
vifrs.append(rec)
|
||||
domid = vm_rec.get('domid')
|
||||
host = vm_rec.get('resident_on')
|
||||
host_rec = session.xenapi.host.get_record(host)
|
||||
uuid = host_rec.get('uuid')
|
||||
util.SMlog("OVSINFO: (domid:%s, uuid:%s)" % (domid, uuid))
|
||||
return (domid, vifrs, uuid)
|
||||
|
||||
except:
|
||||
util.SMlog("### Failed to get domid or vif list for vm ##" + vm_name)
|
||||
return 'false'
|
||||
|
||||
return (-1, [])
|
||||
|
||||
def ovs_set_tag_and_flow(session, args):
|
||||
bridge = args.pop('bridge')
|
||||
vm_name = args.pop('vmName')
|
||||
vlanStr = args.pop('vlans')
|
||||
seqno = args.pop('seqno')
|
||||
|
||||
(domid, vifrs, hostuuid) = ovs_get_domid_vifrs_hostuuid(session, vm_name)
|
||||
|
||||
if domid == '-1':
|
||||
util.SMlog("### Failed to get domid for vm (-1): " + vm_name)
|
||||
return 'false'
|
||||
return 'NO_DOMID'
|
||||
|
||||
if len(vifrs) == 0:
|
||||
return 'SUCCESS'
|
||||
@ -587,12 +769,20 @@ def ovs_set_tag_and_flow(session, args):
|
||||
if vlanStr.startswith("/"): vlanStr = vlanStr[1:]
|
||||
if vlanStr.endswith("/"): vlanStr = vlanStr[:-1]
|
||||
vlans = vlanStr.split("/")
|
||||
vifNames = []
|
||||
macs = []
|
||||
for vifr in vifrs:
|
||||
vifName = "vif" + domid + "." + vifr[0]
|
||||
vifNames.append(vifName)
|
||||
mac = vifr[1]
|
||||
macs.append(mac)
|
||||
vlanRemapUtils(session, {"op":"setTag", "vifName":vifName, "bridge":bridge, "tag":vlans[0]})
|
||||
vlanRemapUtils(session, {"op":"createFlow", "vifName":vifName, "bridge":bridge, "mac":mac, "remap":vlanStr})
|
||||
|
||||
res = ovs_write_vm_log(bridge, vm_name, domid, seqno, vifNames, macs, vlanStr)
|
||||
if res == 'false':
|
||||
return 'CREATE_LOG_FAILED'
|
||||
|
||||
return 'SUCCESS'
|
||||
|
||||
@echo
|
||||
@ -938,6 +1128,7 @@ def cleanup_rules(session, args):
|
||||
util.SMlog("Failed to cleanup rules !")
|
||||
return '-1';
|
||||
|
||||
|
||||
@echo
|
||||
def check_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno):
|
||||
vm_name = vmName;
|
||||
@ -1107,5 +1298,5 @@ def network_rules(session, args):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi, "gethostvmstats": gethostvmstats, "getvncport": getvncport, "getgateway": getgateway, "preparemigration": preparemigration, "setIptables": setIptables, "pingdomr": pingdomr, "pingxenserver": pingxenserver, "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, "networkUsage": networkUsage, "network_rules":network_rules, "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn,"cleanup_rules":cleanup_rules,"vlanRemapUtils":vlanRemapUtils, "ovs_set_tag_and_flow":ovs_set_tag_and_flow})
|
||||
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi, "gethostvmstats": gethostvmstats, "getvncport": getvncport, "getgateway": getgateway, "preparemigration": preparemigration, "setIptables": setIptables, "pingdomr": pingdomr, "pingxenserver": pingxenserver, "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, "networkUsage": networkUsage, "network_rules":network_rules, "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn, "vlanRemapUtils":vlanRemapUtils, "ovs_set_tag_and_flow":ovs_set_tag_and_flow, "ovs_get_vm_log":ovs_get_vm_log,"ovs_delete_flow":ovs_delete_flow,"cleanup_rules":cleanup_rules})
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ public class OvsElement extends AdapterBase implements NetworkElement {
|
||||
}
|
||||
|
||||
if (network.getTrafficType() == Networks.TrafficType.Guest) {
|
||||
_ovsNetworkMgr.CheckAndUpdateDhcpFlow(network);
|
||||
_ovsNetworkMgr.CheckAndUpdateDhcpFlow(network, vm.getVirtualMachine());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
114
server/src/com/cloud/network/ovs/OvsListener.java
Normal file
114
server/src/com/cloud/network/ovs/OvsListener.java
Normal file
@ -0,0 +1,114 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.agent.Listener;
|
||||
import com.cloud.agent.api.AgentControlAnswer;
|
||||
import com.cloud.agent.api.AgentControlCommand;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.PingRoutingWithOvsCommand;
|
||||
import com.cloud.agent.api.StartupCommand;
|
||||
import com.cloud.exception.ConnectionException;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.Status;
|
||||
import com.cloud.network.ovs.dao.OvsWorkDao;
|
||||
import com.cloud.network.ovs.dao.OvsWorkVO.Step;
|
||||
|
||||
public class OvsListener implements Listener {
|
||||
public static final Logger s_logger = Logger.getLogger(OvsListener.class.getName());
|
||||
OvsNetworkManager _ovsNetworkMgr;
|
||||
OvsWorkDao _workDao;
|
||||
|
||||
public OvsListener(OvsNetworkManager ovsMgr, OvsWorkDao workDao) {
|
||||
this._ovsNetworkMgr = ovsMgr;
|
||||
this._workDao = workDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
|
||||
Set<Long> failedFlowVms = new HashSet<Long>();
|
||||
|
||||
for (Answer ans: answers) {
|
||||
if (ans instanceof OvsCreateGreTunnelAnswer) {
|
||||
OvsCreateGreTunnelAnswer r = (OvsCreateGreTunnelAnswer)ans;
|
||||
String s = String.format("(hostIP:%1$s, remoteIP:%2$s, bridge:%3$s, greKey:%4$s)",
|
||||
r.getHostIp(), r.getRemoteIp(),
|
||||
r.getBridge(), r.getKey());
|
||||
if (!r.getResult()) {
|
||||
s_logger.warn("Create GRE tunnel failed due to " + r.getDetails() + s);
|
||||
} else {
|
||||
s_logger.info("Create GRE tunnel success" + s);
|
||||
}
|
||||
} else if (ans instanceof OvsSetTagAndFlowAnswer) {
|
||||
OvsSetTagAndFlowAnswer r = (OvsSetTagAndFlowAnswer)ans;
|
||||
if (!r.getResult()) {
|
||||
s_logger.warn("Failed to set flow for VM " + r.getVmId());
|
||||
_workDao.updateStep(r.getVmId(), r.getSeqNo(), Step.Error);
|
||||
failedFlowVms.add(r.getVmId());
|
||||
} else {
|
||||
s_logger.info("Success to set flow for VM " + r.getVmId());
|
||||
_workDao.updateStep(r.getVmId(), r.getSeqNo(), Step.Done);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: handle delete failure
|
||||
}
|
||||
|
||||
if (failedFlowVms.size() > 0) {
|
||||
_ovsNetworkMgr.scheduleFlowUpdateToHosts(failedFlowVms, false, new Long(10*1000l));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processCommands(long agentId, long seq, Command[] commands) {
|
||||
boolean processed = false;
|
||||
for (Command cmd : commands) {
|
||||
if (cmd instanceof PingRoutingWithOvsCommand) {
|
||||
PingRoutingWithOvsCommand ping = (PingRoutingWithOvsCommand)cmd;
|
||||
if (ping !=null && ping.getStates().size() > 0) {
|
||||
_ovsNetworkMgr.fullSync(ping.getStates());
|
||||
}
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgentControlAnswer processControlCommand(long agentId,
|
||||
AgentControlCommand cmd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processConnect(HostVO host, StartupCommand cmd)
|
||||
throws ConnectionException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDisconnect(long agentId, Status state) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecurring() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeout() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processTimeout(long agentId, long seq) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,13 +1,20 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.cloud.agent.manager.Commands;
|
||||
import com.cloud.deploy.DeployDestination;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.resource.ServerResource;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.vm.DomainRouterVO;
|
||||
import com.cloud.vm.State;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
|
||||
public interface OvsNetworkManager extends Manager {
|
||||
@ -27,11 +34,15 @@ public interface OvsNetworkManager extends Manager {
|
||||
VirtualMachineProfile<DomainRouterVO> profile,
|
||||
DeployDestination dest);
|
||||
|
||||
public void CheckAndUpdateDhcpFlow(Network nw);
|
||||
public void CheckAndUpdateDhcpFlow(Network nw, VirtualMachine vm);
|
||||
|
||||
public void handleVmStateTransition(UserVm userVm, State vmState);
|
||||
public void handleVmStateTransition(VMInstanceVO userVm, State vmState);
|
||||
|
||||
public void RouterCheckAndCreateTunnel(Commands cmds,
|
||||
VirtualMachineProfile<DomainRouterVO> profile,
|
||||
DeployDestination dest);
|
||||
|
||||
public void fullSync(List<Pair<String, Long>> states);
|
||||
|
||||
public void scheduleFlowUpdateToHosts(Set<Long> affectedVms, boolean updateSeqno, Long delayMs);
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ import com.cloud.network.ovs.dao.VlanMappingVO;
|
||||
import com.cloud.network.ovs.dao.VmFlowLogDao;
|
||||
import com.cloud.network.ovs.dao.VmFlowLogVO;
|
||||
import com.cloud.server.ManagementServer;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ComponentLocator;
|
||||
@ -54,6 +56,7 @@ import com.cloud.vm.VirtualMachineProfile;
|
||||
import com.cloud.vm.dao.DomainRouterDao;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
@Local(value={OvsNetworkManager.class})
|
||||
public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
@ -70,10 +73,13 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
@Inject OvsWorkDao _workDao;
|
||||
@Inject VmFlowLogDao _flowLogDao;
|
||||
@Inject UserVmDao _userVMDao;
|
||||
@Inject VMInstanceDao _instanceDao;
|
||||
@Inject AccountDao _accountDao;
|
||||
String _name;
|
||||
boolean _isEnabled;
|
||||
ScheduledExecutorService _executorPool;
|
||||
ScheduledExecutorService _cleanupExecutor;
|
||||
OvsListener _ovsListener;
|
||||
|
||||
private long _serverId;
|
||||
private final long _timeBetweenCleanups = 30; //seconds
|
||||
@ -109,6 +115,8 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
_serverId = ((ManagementServer)ComponentLocator.getComponent(ManagementServer.Name)).getId();
|
||||
_executorPool = Executors.newScheduledThreadPool(10, new NamedThreadFactory("OVS"));
|
||||
_cleanupExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("OVS-Cleanup"));
|
||||
_ovsListener = new OvsListener(this, _workDao);
|
||||
_agentMgr.registerForHostEvents(_ovsListener, true, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -198,16 +206,17 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
if (vm != null && vm.getState() == State.Running) {
|
||||
agentId = vm.getHostId();
|
||||
if (agentId != null ) {
|
||||
//TODO: set flow here
|
||||
OvsSetTagAndFlowCommand cmd = new OvsSetTagAndFlowCommand(vm.getName(),vlans);
|
||||
OvsSetTagAndFlowCommand cmd = new OvsSetTagAndFlowCommand(
|
||||
vm.getName(), vlans, seqnum.toString(), vm.getId());
|
||||
Commands cmds = new Commands(cmd);
|
||||
try {
|
||||
//_agentMgr.send(agentId, cmds, _answerListener);
|
||||
_agentMgr.send(agentId, cmds, null);
|
||||
//TODO: clean dirty in answerListener
|
||||
_agentMgr.send(agentId, cmds, _ovsListener);
|
||||
// TODO: clean dirty in answerListener
|
||||
} catch (AgentUnavailableException e) {
|
||||
s_logger.debug("Unable to send updates for vm: " + userVmId + "(agentid=" + agentId + ")");
|
||||
_workDao.updateStep(work.getInstanceId(), seqnum, Step.Done);
|
||||
s_logger.debug("Unable to send updates for vm: "
|
||||
+ userVmId + "(agentid=" + agentId + ")");
|
||||
_workDao.updateStep(work.getInstanceId(), seqnum,
|
||||
Step.Done);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -283,6 +292,7 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
vlans.add(new Long(vo.getVlan()));
|
||||
}
|
||||
|
||||
assert vlans.size() > 0 : "Vlan map can't be null";
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (Long i : vlans) {
|
||||
buf.append("/");
|
||||
@ -331,9 +341,11 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
HostVO rHost = _hostDao.findById(i.longValue());
|
||||
cmds.addCommand(
|
||||
0, new OvsCreateGreTunnelCommand(rHost.getPrivateIpAddress(), "1"));
|
||||
_agentMgr.send(i.longValue(), new OvsCreateGreTunnelCommand(myIp, "1"));
|
||||
Commands cmd2s = new Commands( new OvsCreateGreTunnelCommand(myIp, "1"));
|
||||
_agentMgr.send(i.longValue(), cmd2s , _ovsListener);
|
||||
s_logger.debug("Ask host " + i.longValue() + " to create gre tunnel to " + hostId);
|
||||
}
|
||||
_vlanMappingDirtyDao.markDirty(accountId);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -375,11 +387,15 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
|
||||
assert nic!=null : "Why there is no guest network nic???";
|
||||
String vlans = parseVlanAndMapping(nic.getBroadcastUri().toASCIIString());
|
||||
cmds.addCommand(new OvsSetTagAndFlowCommand(instance.getName(), vlans));
|
||||
VmFlowLogVO log = _flowLogDao.findOrNewByVmId(instance.getId(), instance.getName());
|
||||
cmds.addCommand(new OvsSetTagAndFlowCommand(instance.getName(), vlans,
|
||||
Long.toString(log.getLogsequence()), instance.getId()));
|
||||
}
|
||||
|
||||
|
||||
//FIXME: if at this router is not start, this will hang 10 secs due to host
|
||||
//plugin cannot found vif for router.
|
||||
@Override
|
||||
public void CheckAndUpdateDhcpFlow(Network nw) {
|
||||
public void CheckAndUpdateDhcpFlow(Network nw, VirtualMachine vm) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
@ -396,8 +412,9 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
|
||||
try {
|
||||
String vlans = getVlanMapping(accountId);
|
||||
VmFlowLogVO log = _flowLogDao.findOrNewByVmId(vm.getId(), vm.getName());
|
||||
_agentMgr.send(router.getHostId(), new OvsSetTagAndFlowCommand(
|
||||
router.getName(), vlans));
|
||||
router.getName(), vlans, Long.toString(log.getLogsequence()), vm.getId()));
|
||||
s_logger.debug("ask router " + router.getName() + " on host "
|
||||
+ router.getHostId() + " update vlan map to " + vlans);
|
||||
} catch (Exception e) {
|
||||
@ -405,7 +422,9 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: handle router
|
||||
@DB
|
||||
@Override
|
||||
public void scheduleFlowUpdateToHosts(Set<Long> affectedVms, boolean updateSeqno, Long delayMs) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
@ -430,11 +449,7 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
s_logger.warn("Ovs failed to acquire lock on vm id " + vmId);
|
||||
continue;
|
||||
}
|
||||
log = _flowLogDao.findByVmId(vmId);
|
||||
if (log == null) {
|
||||
log = new VmFlowLogVO(vmId);
|
||||
log = _flowLogDao.persist(log);
|
||||
}
|
||||
log = _flowLogDao.findOrNewByVmId(vmId, vm.getName());
|
||||
|
||||
if (log != null && updateSeqno){
|
||||
log.incrLogsequence();
|
||||
@ -461,8 +476,8 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected Set<Long> getAffectedVms(UserVm userVm) {
|
||||
long accountId = userVm.getAccountId();
|
||||
protected Set<Long> getAffectedVms(VMInstanceVO instance) {
|
||||
long accountId = instance.getAccountId();
|
||||
if (!_vlanMappingDirtyDao.isDirty(accountId)) {
|
||||
return null;
|
||||
}
|
||||
@ -475,36 +490,47 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
return affectedVms;
|
||||
}
|
||||
|
||||
protected void handleVmStateChange(UserVm userVm) {
|
||||
Set<Long> affectedVms = getAffectedVms(userVm);
|
||||
protected void handleVmStateChange(VMInstanceVO instance) {
|
||||
Set<Long> affectedVms = getAffectedVms(instance);
|
||||
scheduleFlowUpdateToHosts(affectedVms, true, null);
|
||||
_vlanMappingDirtyDao.clean(instance.getAccountId());
|
||||
s_logger.debug("Clean dirty for account " + instance.getAccountId());
|
||||
}
|
||||
|
||||
//TODO: think about lock
|
||||
protected void checkAndRemove(UserVm userVm) {
|
||||
long accountId = userVm.getAccountId();
|
||||
long hostId = userVm.getHostId();
|
||||
@DB
|
||||
protected void checkAndRemove(VMInstanceVO instance) {
|
||||
long accountId = instance.getAccountId();
|
||||
long hostId = instance.getHostId();
|
||||
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
VlanMappingVO vo = _vlanMappingDao.findByAccountIdAndHostId(accountId, hostId);
|
||||
if (vo.unref() == 0) {
|
||||
_vlanMappingDao.remove(vo.getId());
|
||||
s_logger.debug(userVm.getName() + " is the last one on host "
|
||||
s_logger.debug(instance.getName() + " is the last one on host "
|
||||
+ hostId + " for account " + accountId
|
||||
+ ", remove vlan in ovs_host_vlan_alloc");
|
||||
_vlanMappingDirtyDao.markDirty(accountId);
|
||||
} else {
|
||||
_vlanMappingDao.update(vo.getId(), vo);
|
||||
s_logger.debug(userVm.getName()
|
||||
s_logger.debug(instance.getName()
|
||||
+ " reduces reference count of (account,host) = ("
|
||||
+ accountId + "," + hostId + ") to " + vo.getRef());
|
||||
}
|
||||
_flowLogDao.deleteByVmId(instance.getId());
|
||||
txn.commit();
|
||||
|
||||
try {
|
||||
Commands cmds = new Commands(new OvsDeleteFlowCommand(instance.getName()));
|
||||
_agentMgr.send(hostId, cmds, _ovsListener);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleVmStateTransition(UserVm userVm, State vmState) {
|
||||
public void handleVmStateTransition(VMInstanceVO instance, State vmState) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
@ -519,12 +545,12 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
case Unknown:
|
||||
return;
|
||||
case Running:
|
||||
handleVmStateChange(userVm);
|
||||
handleVmStateChange(instance);
|
||||
break;
|
||||
case Stopping:
|
||||
case Stopped:
|
||||
checkAndRemove(userVm);
|
||||
handleVmStateChange(userVm);
|
||||
checkAndRemove(instance);
|
||||
handleVmStateChange(instance);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -557,4 +583,53 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
applyDefaultFlow(cmds, profile.getVirtualMachine(), dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fullSync(List<Pair<String, Long>> states) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO:debug code, remove in future
|
||||
List<AccountVO> accounts = _accountDao.listAll();
|
||||
for (AccountVO acnt : accounts) {
|
||||
if (_vlanMappingDirtyDao.isDirty(acnt.getId())) {
|
||||
s_logger.warn("Vlan mapping for account "
|
||||
+ acnt.getAccountName() + " id " + acnt.getId()
|
||||
+ " is dirty");
|
||||
}
|
||||
}
|
||||
|
||||
if (states.size() ==0) {
|
||||
s_logger.info("Nothing to do, Ovs fullsync is happy");
|
||||
return;
|
||||
}
|
||||
|
||||
Set<Long>vmIds = new HashSet<Long>();
|
||||
for (Pair<String, Long>state : states) {
|
||||
if (state.second() == -1) {
|
||||
s_logger.warn("Ovs fullsync get wrong seqno for " + state.first());
|
||||
continue;
|
||||
}
|
||||
VmFlowLogVO log = _flowLogDao.findByName(state.first());
|
||||
if (log.getLogsequence() != state.second()) {
|
||||
s_logger.debug("Ovs fullsync detected unmatch seq number for " + state.first() + ", run sync");
|
||||
VMInstanceVO vo = _instanceDao.findById(log.getInstanceId());
|
||||
if (vo == null) {
|
||||
s_logger.warn("Ovs can't find " + state.first() + " in vm_instance!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vo.getType() != VirtualMachine.Type.User && vo.getType() != VirtualMachine.Type.DomainRouter) {
|
||||
s_logger.warn("Ovs fullsync: why we sync a " + vo.getType().toString() + " VM???");
|
||||
continue;
|
||||
}
|
||||
vmIds.add(new Long(vo.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
if (vmIds.size() > 0) {
|
||||
scheduleFlowUpdateToHosts(vmIds, true, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import java.util.List;
|
||||
import javax.ejb.Local;
|
||||
import com.cloud.ha.HaWorkVO;
|
||||
import com.cloud.network.ovs.dao.OvsWorkVO.Step;
|
||||
import com.cloud.utils.db.DB;
|
||||
import com.cloud.utils.db.Filter;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
@ -115,6 +116,7 @@ public class OvsWorkDaoImpl extends GenericDaoBase<OvsWorkVO, Long> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public void updateStep(Long vmId, Long logSequenceNumber, Step step) {
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
@ -183,5 +185,5 @@ public class OvsWorkDaoImpl extends GenericDaoBase<OvsWorkVO, Long> implements
|
||||
update(work, sc);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,4 +4,7 @@ import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface VmFlowLogDao extends GenericDao<VmFlowLogVO, Long> {
|
||||
VmFlowLogVO findByVmId(long vmId);
|
||||
VmFlowLogVO findOrNewByVmId(long vmId, String name);
|
||||
VmFlowLogVO findByName(String name);
|
||||
void deleteByVmId(long vmId);
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import javax.ejb.Local;
|
||||
public class VmFlowLogDaoImpl extends GenericDaoBase<VmFlowLogVO, Long>
|
||||
implements VmFlowLogDao {
|
||||
private SearchBuilder<VmFlowLogVO> VmIdSearch;
|
||||
private SearchBuilder<VmFlowLogVO> VmNameSearch;
|
||||
|
||||
@Override
|
||||
public VmFlowLogVO findByVmId(long vmId) {
|
||||
@ -22,6 +23,35 @@ public class VmFlowLogDaoImpl extends GenericDaoBase<VmFlowLogVO, Long>
|
||||
VmIdSearch.and("vmId", VmIdSearch.entity().getInstanceId(),
|
||||
SearchCriteria.Op.EQ);
|
||||
VmIdSearch.done();
|
||||
|
||||
VmNameSearch = createSearchBuilder();
|
||||
VmNameSearch.and("name", VmNameSearch.entity().getName(),
|
||||
SearchCriteria.Op.EQ);
|
||||
VmNameSearch.done();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public VmFlowLogVO findOrNewByVmId(long vmId, String name) {
|
||||
VmFlowLogVO log = findByVmId(vmId);
|
||||
if (log == null) {
|
||||
log = new VmFlowLogVO(vmId, name);
|
||||
log = persist(log);
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByVmId(long vmId) {
|
||||
SearchCriteria<VmFlowLogVO> sc = VmIdSearch.create();
|
||||
sc.setParameters("vmId", vmId);
|
||||
expunge(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VmFlowLogVO findByName(String name) {
|
||||
SearchCriteria<VmFlowLogVO> sc = VmNameSearch.create();
|
||||
sc.setParameters("name", name);
|
||||
return findOneIncludingRemovedBy(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,13 +28,17 @@ public class VmFlowLogVO {
|
||||
@Column(name="logsequence")
|
||||
long logsequence;
|
||||
|
||||
@Column(name="vm_name", updatable=false, nullable=false, length=255)
|
||||
protected String name = null;
|
||||
|
||||
protected VmFlowLogVO() {
|
||||
|
||||
}
|
||||
|
||||
public VmFlowLogVO(Long instanceId) {
|
||||
public VmFlowLogVO(Long instanceId, String name) {
|
||||
super();
|
||||
this.instanceId = instanceId;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@ -56,4 +60,8 @@ public class VmFlowLogVO {
|
||||
public void incrLogsequence() {
|
||||
logsequence++;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@ -738,11 +738,6 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeStartCommand(final DomainRouterVO router) {
|
||||
_itMgr.stateTransitTo(router, VirtualMachine.Event.AgentReportRunning, router.getHostId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeStopCommand(final DomainRouterVO router) {
|
||||
completeStopCommand(router, VirtualMachine.Event.AgentReportStopped);
|
||||
@ -1359,6 +1354,8 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
return false;
|
||||
}
|
||||
|
||||
DomainRouterVO router = profile.getVirtualMachine();
|
||||
_ovsNetworkMgr.handleVmStateTransition(router, State.Running);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1367,6 +1364,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
if (answer != null && answer.length > 0) {
|
||||
processStopOrRebootAnswer(profile.getVirtualMachine(), answer[0]);
|
||||
}
|
||||
|
||||
DomainRouterVO router = profile.getVirtualMachine();
|
||||
_ovsNetworkMgr.handleVmStateTransition(router, State.Stopped);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1870,4 +1870,8 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
return routersToStop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeStartCommand(DomainRouterVO router) {
|
||||
_itMgr.stateTransitTo(router, VirtualMachine.Event.AgentReportRunning, router.getHostId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1128,14 +1128,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
throw new CloudRuntimeException("Shouldn't even be here!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeStartCommand(UserVmVO vm) {
|
||||
_itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportRunning, vm.getHostId());
|
||||
_networkGroupMgr.handleVmStateTransition(vm, State.Running);
|
||||
_ovsNetworkMgr.handleVmStateTransition(vm, State.Running);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void completeStopCommand(UserVmVO instance) {
|
||||
completeStopCommand(1L, instance, VirtualMachine.Event.AgentReportStopped);
|
||||
@ -1166,8 +1159,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
_networkGroupMgr.handleVmStateTransition(vm, State.Stopped);
|
||||
_ovsNetworkMgr.handleVmStateTransition(vm, State.Stopped);
|
||||
} catch (Throwable th) {
|
||||
s_logger.error("Error during stop: ", th);
|
||||
throw new CloudRuntimeException("Error during stop: ", th);
|
||||
@ -2408,7 +2399,10 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
|
||||
@Override
|
||||
public boolean finalizeStart(Commands cmds, VirtualMachineProfile<UserVmVO> profile, DeployDestination dest, ReservationContext context) {
|
||||
return true;
|
||||
UserVmVO vm = profile.getVirtualMachine();
|
||||
_networkGroupMgr.handleVmStateTransition(vm, State.Running);
|
||||
_ovsNetworkMgr.handleVmStateTransition(vm, State.Running);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2460,6 +2454,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
|
||||
@Override
|
||||
public void finalizeStop(VirtualMachineProfile<UserVmVO> profile, long hostId, String reservationId, Answer...answer) {
|
||||
UserVmVO vm = profile.getVirtualMachine();
|
||||
_networkGroupMgr.handleVmStateTransition(vm, State.Stopped);
|
||||
_ovsNetworkMgr.handleVmStateTransition(vm, State.Stopped);
|
||||
}
|
||||
|
||||
public String generateRandomPassword() {
|
||||
@ -2520,6 +2517,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
throw new CloudRuntimeException("Failed to destroy vm with id " + vmId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeStartCommand(UserVmVO vm) {
|
||||
_itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportRunning, vm.getHostId());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
@ -31,6 +31,7 @@ import org.apache.log4j.Logger;
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.AgentManager.OnError;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.StartAnswer;
|
||||
import com.cloud.agent.api.StartCommand;
|
||||
import com.cloud.agent.api.StopAnswer;
|
||||
import com.cloud.agent.api.StopCommand;
|
||||
@ -388,6 +389,17 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Cluster
|
||||
}
|
||||
}
|
||||
|
||||
private Answer getStartAnswer(Answer[] answers) {
|
||||
for (Answer ans : answers) {
|
||||
if (ans instanceof StartAnswer) {
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
|
||||
assert 1 == 0 : "Why there is no Start Answer???";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends VMInstanceVO> T advanceStart(T vm, Map<String, Object> params, User caller, Account account, HypervisorType hyperType) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
|
||||
State state = vm.getState();
|
||||
@ -495,7 +507,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Cluster
|
||||
vmGuru.finalizeDeployment(cmds, vmProfile, dest, context);
|
||||
try {
|
||||
Answer[] answers = _agentMgr.send(dest.getHost().getId(), cmds);
|
||||
if (answers[0].getResult() && vmGuru.finalizeStart(cmds, vmProfile, dest, context)) {
|
||||
if (getStartAnswer(answers).getResult() && vmGuru.finalizeStart(cmds, vmProfile, dest, context)) {
|
||||
if (!stateTransitTo(vm, Event.OperationSucceeded, dest.getHost().getId())) {
|
||||
throw new CloudRuntimeException("Unable to transition to a new state.");
|
||||
}
|
||||
|
||||
@ -1344,6 +1344,7 @@ CREATE TABLE `cloud`.`ovs_vm_flow_log` (
|
||||
`instance_id` bigint unsigned NOT NULL COMMENT 'vm instance that needs flows to be synced.',
|
||||
`created` datetime NOT NULL COMMENT 'time the entry was requested',
|
||||
`logsequence` bigint unsigned COMMENT 'seq number to be sent to agent, uniquely identifies flow update',
|
||||
`vm_name` varchar(255) NOT NULL COMMENT 'vm name',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user