Change in vdsm[master]: multipath: Move all calls to multipath exe to a single method
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: multipath: Move all calls to multipath exe to a single method
......................................................................
multipath: Move all calls to multipath exe to a single method
This makes the code a bit cleaner
Change-Id: I52afc07a07a925ed7572eb369deb7c203edb04cd
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M vdsm/storage/multipath.py
1 file changed, 11 insertions(+), 4 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/55/19255/1
diff --git a/vdsm/storage/multipath.py b/vdsm/storage/multipath.py
index 924d747..c31b5c3 100644
--- a/vdsm/storage/multipath.py
+++ b/vdsm/storage/multipath.py
@@ -94,6 +94,10 @@
)
+def _runCmd(args):
+ return misc.execCmd([constants.EXT_MULTIPATH] + args, sudo=True)
+
+
def rescan():
"""
Forces multipath daemon to rescan the list of available devices and
@@ -108,8 +112,8 @@
supervdsm.getProxy().forceScsiScan()
# Now let multipath daemon pick up new devices
- cmd = [constants.EXT_MULTIPATH, "-r"]
- misc.execCmd(cmd, sudo=True)
+
+ _runCmd("-r")
def isEnabled():
@@ -154,6 +158,10 @@
return False
+def flushAll():
+ _runCmd("-F")
+
+
def setupMultipath():
"""
Set up the multipath daemon configuration to the known and
@@ -173,8 +181,7 @@
raise se.MultipathSetupError()
misc.persistFile(MPATH_CONF)
- # Flush all unused multipath device maps
- misc.execCmd([constants.EXT_MULTIPATH, "-F"], sudo=True)
+ flushAll()
cmd = [constants.EXT_VDSM_TOOL, "service-reload", "multipathd"]
rc = misc.execCmd(cmd, sudo=True)[0]
--
To view, visit http://gerrit.ovirt.org/19255
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I52afc07a07a925ed7572eb369deb7c203edb04cd
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years
Change in vdsm[master]: supervdsm: log actual error in ProxyCaller
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: supervdsm: log actual error in ProxyCaller
......................................................................
supervdsm: log actual error in ProxyCaller
Change-Id: Id8a1c83d2a963002d3c793398bb62679b77f5f47
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M vdsm/supervdsm.py
1 file changed, 2 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/75/35475/1
diff --git a/vdsm/supervdsm.py b/vdsm/supervdsm.py
index d6b0209..46247f2 100644
--- a/vdsm/supervdsm.py
+++ b/vdsm/supervdsm.py
@@ -37,6 +37,7 @@
class ProxyCaller(object):
+ log = logging.getLogger("supervdsm.ProxyCaller")
def __init__(self, supervdsmProxy, funcName):
self._funcName = funcName
@@ -50,6 +51,7 @@
return callMethod()
except RemoteError:
self._supervdsmProxy._connect()
+ self.log.exception("Could not call method")
raise RuntimeError(
"Broken communication with supervdsm. Failed call to %s"
% self._funcName)
--
To view, visit http://gerrit.ovirt.org/35475
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id8a1c83d2a963002d3c793398bb62679b77f5f47
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years
Change in vdsm[master]: [WIP]Java Bindings: Proton support in Java Bindings
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: [WIP]Java Bindings: Proton support in Java Bindings
......................................................................
[WIP]Java Bindings: Proton support in Java Bindings
Change-Id: I94c52e118cb63d7df84b89a9b93da7b9e477be91
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
A client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonAuthenticator.java
A client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonClient.java
A client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonListener.java
A client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonReactor.java
A client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/AmqpReactorTestHelper.java
A client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/TestJsonRpcClientAMQP.java
6 files changed, 844 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/28/15428/1
diff --git a/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonAuthenticator.java b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonAuthenticator.java
new file mode 100644
index 0000000..35c9099
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonAuthenticator.java
@@ -0,0 +1,98 @@
+package org.ovirt.vdsm.reactors;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.qpid.proton.driver.Connector;
+import org.apache.qpid.proton.engine.Sasl;
+import org.apache.qpid.proton.engine.Sasl.SaslOutcome;
+import org.apache.qpid.proton.engine.Sasl.SaslState;
+import org.ovirt.vdsm.reactors.ProtonAuthenticator.AuthenticatorType;
+
+public final class ProtonAuthenticator {
+
+ public enum AuthenticatorType {
+
+ SERVER, CLIENT
+ }
+
+ public enum ConnectionState {
+
+ AUTHENTICATING, CONNECTED, FAILED
+ }
+ private ConnectionState _state;
+ final private AuthenticatorType _authType;
+ final private Connector<?> _connector;
+
+ public ProtonAuthenticator(Connector<?> connector,
+ AuthenticatorType authType) {
+ _authType = authType;
+ setState(ConnectionState.AUTHENTICATING);
+ _connector = connector;
+ final Sasl sasl = _connector.sasl();
+ if (authType == AuthenticatorType.CLIENT) {
+ sasl.setMechanisms(new String[]{"ANONYMOUS"});
+ sasl.client();
+ }
+ }
+
+ private void setState(ConnectionState state) {
+ _state = state;
+ }
+
+ public ConnectionState getState() {
+ return _state;
+ }
+
+ public void authenticate() {
+ final Sasl sasl = _connector.sasl();
+
+ while (true) {
+ try {
+ this._connector.process();
+ } catch (IOException ex) {
+ return;
+ }
+ final SaslState state = sasl.getState();
+ switch (state) {
+ case PN_SASL_CONF:
+ if (_authType == AuthenticatorType.SERVER) {
+ sasl.setMechanisms(new String[]{"ANONYMOUS"});
+ sasl.server();
+ }
+ break;
+ case PN_SASL_STEP:
+ if (_authType == AuthenticatorType.SERVER) {
+ final String[] mechs = sasl.getRemoteMechanisms();
+ if (mechs.length < 1) {
+ sasl.done(SaslOutcome.PN_SASL_AUTH);
+ break;
+ }
+
+ final String mech = mechs[0];
+ if (mech.equals("ANONYMOUS")) {
+ sasl.done(SaslOutcome.PN_SASL_OK);
+ } else {
+ sasl.done(SaslOutcome.PN_SASL_AUTH);
+ }
+ }
+ return;
+ case PN_SASL_PASS:
+ this.setState(ConnectionState.CONNECTED);
+ return;
+ case PN_SASL_FAIL:
+ this.setState(ConnectionState.FAILED);
+ return;
+ case PN_SASL_IDLE:
+
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+ public AuthenticatorType getAuthType() {
+ return _authType;
+ }
+}
diff --git a/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonClient.java b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonClient.java
new file mode 100644
index 0000000..4baffbf
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonClient.java
@@ -0,0 +1,224 @@
+package org.ovirt.vdsm.reactors;
+
+import java.nio.ByteBuffer;
+import java.util.Calendar;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Future;
+
+import javax.swing.event.EventListenerList;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.Data;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.Link;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.engine.Session;
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.message.MessageFactory;
+import org.apache.qpid.proton.message.impl.MessageFactoryImpl;
+
+public final class ProtonClient implements ReactorClient {
+ private final ProtonReactor _reactor;
+ final private Session _ssn;
+
+ private Sender _sender;
+ private Receiver _receiver;
+
+ private final int _CREDIT = 10;
+ private final ConcurrentLinkedQueue<ByteBuffer> _outbox;
+ private final EventListenerList _eventListeners;
+ private final int _deliveryTimeoutSec;
+ private final MessageFactory _msgFactory;
+
+ public ProtonClient(ProtonReactor reactor, Session session) {
+ _ssn = session;
+ _sender = null;
+ _receiver = null;
+ _outbox = new ConcurrentLinkedQueue<>();
+ _eventListeners = new EventListenerList();
+ _deliveryTimeoutSec = 60 * 3;
+ _reactor = reactor;
+ _msgFactory = new MessageFactoryImpl();
+ }
+
+ @Override
+ public void addEventListener(EventListener el) {
+ synchronized (_eventListeners) {
+ _eventListeners.add(EventListener.class, el);
+ }
+ }
+
+ @Override
+ public void removeEventListener(EventListener el) {
+ synchronized (_eventListeners) {
+ _eventListeners.remove(EventListener.class, el);
+ }
+ }
+
+ private void emitOnMessageReceived(ByteBuffer message) {
+ synchronized (_eventListeners) {
+ final Class<EventListener> cls = EventListener.class;
+ final EventListener[] els = _eventListeners.getListeners(cls);
+ for (EventListener el : els) {
+ el.onMessageReceived(this, message);
+ }
+ }
+ }
+
+ @Override
+ public void sendMessage(ByteBuffer message) {
+ _outbox.add(message);
+ _reactor.wakeup();
+ }
+
+ public void addLink(Link link) {
+ assert (link.getSession().equals(_ssn));
+
+ if (link instanceof Sender) {
+ if (_sender != null) {
+ // already have a sender
+ link.close();
+ return;
+ }
+
+ _sender = (Sender) link;
+ } else {
+ assert (link instanceof Receiver);
+ if (_receiver != null) {
+ // already have a receiver
+ link.close();
+ return;
+ }
+
+ _receiver = (Receiver) link;
+ _receiver.flow(_CREDIT);
+ }
+ link.open();
+ }
+
+ private Message _popOutgoingMessage() {
+ final ByteBuffer data = _outbox.poll();
+ if (data == null) {
+ return null;
+ }
+
+ final Section body = new Data(Binary.create(data));
+ final Message msg = _msgFactory.createMessage();
+ msg.setBody(body);
+ msg.setAddress(_sender.getTarget().toString());
+ return msg;
+ }
+
+ public void queueDeliveries() {
+ if (_sender == null) {
+ final String uuid = UUID.randomUUID().toString();
+ _sender = _ssn.sender("Sender-" + uuid);
+ }
+
+ while (_sender.getCredit() > 0) {
+ final Message m = _popOutgoingMessage();
+ if (m == null) {
+ return;
+ }
+
+ final String uuid = UUID.randomUUID().toString();
+ final Delivery d = _sender
+ .delivery(("outgoing-" + uuid).getBytes());
+ d.setContext(m);
+ }
+ }
+
+ public void processDelivery(Delivery delivery) {
+ assert (_ssn.equals(delivery.getLink().getSession()));
+
+ if (delivery.isReadable()) {
+ _processIncomingDelivery(delivery);
+ } else {
+ assert (delivery.isWritable());
+ _processOutgoingDelivery(delivery);
+ }
+ }
+
+ private void _processOutgoingDelivery(Delivery delivery) {
+ final Sender link = (Sender) delivery.getLink();
+ assert (link.equals(_sender));
+
+ final Message msg = (Message) delivery.getContext();
+ // TBD: Buffer can be reused forever. Change in case of
+ // performance issues.
+ ByteBuffer buff;
+ int i = 1;
+ int written = 0;
+ do {
+ buff = ByteBuffer.allocate(i * 4096);
+ written = msg.encode(buff.array(), 0, buff.capacity());
+ i++;
+ } while (written == buff.capacity());
+
+ link.send(buff.array(), 0, written);
+ if (link.advance()) {
+ // Attach timeout to the delivery
+ final Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.SECOND, _deliveryTimeoutSec);
+ delivery.setContext(calendar);
+ }
+ }
+
+ private void _processIncomingDelivery(Delivery delivery) {
+ int total = 0;
+ int read = 0;
+ ByteBuffer buff = ByteBuffer.allocate(4096);
+
+ while (read >= 0) {
+ total += read;
+ if (total >= buff.capacity()) {
+ final ByteBuffer buff2 = ByteBuffer
+ .allocate(buff.capacity() * 2);
+ buff2.put(buff);
+ buff = buff2;
+ }
+ read = _receiver.recv(buff.array(), total, buff.capacity() - total);
+ }
+
+ final Message msg = _msgFactory.createMessage();
+ msg.decode(buff.array(), 0, total);
+
+ assert (msg.getBody() instanceof Data);
+ final Data body = (Data) msg.getBody();
+ final ByteBuffer bb = body.getValue().asByteBuffer();
+ delivery.settle();
+ emitOnMessageReceived(bb);
+ }
+
+ @Override
+ public Future<Void> close() {
+ final Session ssn = _ssn;
+ return _reactor.queueOperation(new Callable<Void>() {
+ @Override
+ public Void call() {
+ ssn.close();
+ return null;
+ }
+ });
+ }
+
+ @Override
+ public boolean closed() {
+ return _ssn.getLocalState().equals(EndpointState.CLOSED);
+ }
+
+ public void removeLink(Link link) {
+ if (link.equals(_sender)) {
+ _sender = null;
+ } else {
+ assert (link.equals(_receiver));
+ _receiver = null;
+ }
+ link.close();
+ }
+}
diff --git a/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonListener.java b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonListener.java
new file mode 100644
index 0000000..35896f4
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonListener.java
@@ -0,0 +1,42 @@
+package org.ovirt.vdsm.reactors;
+
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+import org.apache.qpid.proton.driver.Listener;
+
+public final class ProtonListener implements ReactorListener {
+ private final EventListener _eventListener;
+ private Listener<ProtonListener> _listener;
+ private final ProtonReactor _reactor;
+
+ public ProtonListener(ProtonReactor reactor, EventListener eventListener) {
+ _eventListener = eventListener;
+ _reactor = reactor;
+ }
+
+ public void setListener(Listener<ProtonListener> l) {
+ _listener = l;
+ }
+
+ public void accept(ReactorClient client) {
+ _eventListener.onAcccept(this, client);
+ }
+
+ @Override
+ public Future<Void> close() {
+ final Listener<ProtonListener> l = _listener;
+ return _reactor.queueOperation(new Callable<Void>() {
+ @Override
+ public Void call() {
+ try {
+ l.close();
+ } catch (IOException e) {
+ // already closed
+ }
+ return null;
+ }
+ });
+ }
+}
diff --git a/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonReactor.java b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonReactor.java
new file mode 100644
index 0000000..b5a38b4
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonReactor.java
@@ -0,0 +1,452 @@
+package org.ovirt.vdsm.reactors;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+
+import org.apache.qpid.proton.driver.Connector;
+import org.apache.qpid.proton.driver.Driver;
+import org.apache.qpid.proton.driver.Listener;
+import org.apache.qpid.proton.driver.impl.DriverFactoryImpl;
+import org.apache.qpid.proton.engine.Connection;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.engine.Link;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.engine.Session;
+import org.apache.qpid.proton.engine.impl.EngineFactoryImpl;
+import org.ovirt.vdsm.reactors.ProtonAuthenticator.AuthenticatorType;
+import org.ovirt.vdsm.reactors.ProtonAuthenticator.ConnectionState;
+import org.ovirt.vdsm.util.ChainedOperation;
+import org.ovirt.vdsm.util.ReactorScheduler;
+
+public final class ProtonReactor implements Reactor {
+
+ private final Driver _driver;
+ private final ReactorScheduler _scheduler;
+ private boolean _isRunning;
+ final Object _syncRoot = new Object();
+ final ProtonReactor reactor = this;
+ private EngineFactory _engineFactory;
+
+ public boolean isRunning() {
+ return _isRunning;
+ }
+
+ public ProtonReactor() throws IOException {
+ _engineFactory = new EngineFactoryImpl();
+ _driver = new DriverFactoryImpl().createDriver();
+ _isRunning = false;
+ _scheduler = new ReactorScheduler();
+ }
+
+ @Override
+ public void finalize() throws Throwable {
+ try {
+ _driver.destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ // Creates a listener, returns null if failed to bind or reactor is not
+ // running;
+ @Override
+ public Future<ReactorListener> createListener(final String host,
+ final int port,
+ final ReactorListener.EventListener eventListener) {
+
+ return queueOperation(new Callable<ReactorListener>() {
+ @Override
+ public ProtonListener call() {
+
+ final ProtonListener listener = new ProtonListener(reactor, eventListener);
+ final Listener<ProtonListener> l = _driver.createListener(host,
+ port, listener);
+
+ listener.setListener(l);
+
+ if (l == null) {
+ return null;
+ }
+
+ return listener;
+ }
+ });
+ }
+
+ @Override
+ public Future<ReactorClient> createClient(final String host, final int port) {
+ final Driver driver = _driver;
+ final EngineFactory engineFactory = _engineFactory;
+
+ return queueOperation(new ChainedOperation.Operation<ReactorClient>() {
+ final private int _INIT = 1;
+ final private int _AUTHENTICATE = 2;
+ final private int _DONE = 3;
+ private int _state;
+ final private Driver _driver;
+ final private ProtonReactor _reactor;
+ private Connector<ProtonAuthenticator> _connector;
+ private ProtonAuthenticator _auth;
+ private boolean _done;
+ private boolean _cancelled;
+ private ReactorClient _result;
+ private EngineFactory _engineFactory;
+
+ {
+ _driver = driver;
+ _reactor = reactor;
+ _state = _INIT;
+ _done = false;
+ _cancelled = false;
+ _engineFactory = engineFactory;
+ }
+
+ @Override
+ public void call(final boolean cancelled) {
+ switch (_state) {
+ case _INIT:
+ if (cancelled) {
+ _cancelled = true;
+ _done = true;
+ return;
+ }
+
+ _connector = this._driver.createConnector(host, port, null);
+
+ final Connection connection = engineFactory.createConnection();
+ _connector.setConnection(connection);
+ _auth = new ProtonAuthenticator(_connector,
+ AuthenticatorType.CLIENT);
+ _connector.setContext(_auth);
+ connection.open();
+ _state = _AUTHENTICATE;
+ case _AUTHENTICATE:
+ if (cancelled) {
+ _cancelled = true;
+ _close();
+ return;
+ }
+
+ switch (_auth.getState()) {
+ case AUTHENTICATING:
+ _auth.authenticate();
+ try {
+ _connector.process();
+ } catch (IOException e) {
+ // ignore
+ }
+ return;
+ case FAILED:
+ _close();
+ return;
+ case CONNECTED:
+ // Success !
+ break;
+ }
+
+ Session ssn = _connector.getConnection().session();
+ ssn.open();
+ _result = new ProtonClient(_reactor, ssn);
+ ssn.setContext(_result);
+ _done = true;
+ _state = _DONE;
+ }
+ }
+
+ private void _close() {
+ _connector.getConnection().close();
+ _connector.close();
+ _done = true;
+ _result = null;
+ }
+
+ @Override
+ public boolean isDone() {
+ return _done;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return _cancelled;
+ }
+
+ @Override
+ public ReactorClient getResult() {
+ return _result;
+ }
+ });
+ }
+
+ // Queues operation to be run in the serving loop.
+ public <T> Future<T> queueOperation(Callable<T> cb) {
+ final FutureTask<T> task = new FutureTask<>(cb);
+ _queueFuture(task);
+ return task;
+ }
+
+ public <T> Future<T> queueOperation(ChainedOperation.Operation<T> op) {
+ final ChainedOperation<T> task = new ChainedOperation<>(op);
+ _queueFuture(task);
+ return task;
+ }
+
+ private void _queueFuture(Future<?> op) {
+ synchronized (_scheduler) {
+ _scheduler.queueFuture(op);
+ wakeup();
+ }
+ }
+
+ private void _waitEvents() {
+ _driver.doWait(0);
+ }
+
+ public void wakeup() {
+ _driver.wakeup();
+ }
+
+ @Override
+ public void serve() {
+ synchronized (_syncRoot) {
+ _isRunning = true;
+ }
+
+ while (_isRunning) {
+ //_waitEvents();
+ synchronized (_scheduler) {
+ _scheduler.performPendingOperations();
+ }
+ _acceptConnectionRequests();
+ _processConnectors();
+ }
+ }
+
+ private void _processConnectors() {
+ for (Connector<?> connector = _driver.connector(); connector != null; connector = _driver
+ .connector()) {
+ if (connector.isClosed()) {
+ connector.destroy();
+ continue;
+ }
+
+ try {
+ connector.process();
+ } catch (IOException e) {
+ continue;
+ }
+
+ final Object ctx = connector.getContext();
+ assert (ctx instanceof ProtonAuthenticator);
+
+ if (ctx instanceof ProtonAuthenticator) {
+ final ProtonAuthenticator auth = (ProtonAuthenticator) ctx;
+ ConnectionState cs = auth.getState();
+ if (cs.equals(ConnectionState.AUTHENTICATING)) {
+ auth.authenticate();
+ cs = auth.getState();
+ }
+
+ if (cs.equals(ConnectionState.CONNECTED)) {
+ if (connector.getConnection() == null) {
+ connector.setConnection(_engineFactory.createConnection());
+ }
+ _processConnector(connector);
+ }
+ }
+
+ try {
+ connector.process();
+ } catch (IOException e) {
+ continue;
+ }
+ }
+ }
+
+ private void _processConnector(Connector<?> connector) {
+ _initConnection(connector);
+ _openPendingSessions(connector);
+ _openLinks(connector);
+ _queueOutgoingDeliveries(connector);
+ _processDeliveries(connector);
+ _cleanDeliveries(connector);
+ _cleanLinks(connector);
+ _cleanSessions(connector);
+ }
+
+ private void _cleanSessions(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.ACTIVE);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .of(EndpointState.CLOSED);
+
+ for (Session ssn = conn.sessionHead(localState, remoteState); ssn != null; ssn
+ .next(localState, remoteState)) {
+
+ ssn.close();
+ }
+ }
+
+ private void _cleanLinks(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.ACTIVE);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .of(EndpointState.CLOSED);
+
+ for (Link link = conn.linkHead(localState, remoteState); link != null; link = link
+ .next(localState, remoteState)) {
+
+ final ProtonClient ssn = _getClient(link.getSession());
+ ssn.removeLink(link);
+ }
+ }
+
+ private void _cleanDeliveries(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.ACTIVE);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .allOf(EndpointState.class);
+ for (Link link = conn.linkHead(localState, remoteState); link != null; link = link
+ .next(localState, remoteState)) {
+
+ if (link instanceof Receiver) {
+ // We settle all incoming deliveries upon receive
+ continue;
+ }
+
+ Delivery d;
+ final Calendar now = Calendar.getInstance();
+ for (Iterator<Delivery> iter = link.unsettled(); iter.hasNext();) {
+ d = iter.next();
+ Object ctx = d.getContext();
+ if (!(ctx instanceof Calendar)) {
+ // Has not been sent yet
+ continue;
+ }
+
+ final Calendar timeout = (Calendar) ctx;
+ boolean remoteClosed = link.getRemoteState().equals(
+ EndpointState.CLOSED);
+ boolean timedOut = now.after(timeout);
+ if (d.remotelySettled() || timedOut || remoteClosed) {
+ d.settle();
+ d.free();
+ }
+ }
+
+ }
+
+ }
+
+ private void _processDeliveries(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ for (Delivery delivery = conn.getWorkHead(); delivery != null; delivery = delivery
+ .getWorkNext()) {
+
+ final ProtonClient client = _getClient(delivery.getLink()
+ .getSession());
+ client.processDelivery(delivery);
+ }
+ }
+
+ private void _queueOutgoingDeliveries(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.ACTIVE);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .allOf(EndpointState.class);
+
+ for (Session ssn = conn.sessionHead(localState, remoteState); ssn != null; ssn = ssn
+ .next(localState, remoteState)) {
+
+ final ProtonClient client = _getClient(ssn);
+ client.queueDeliveries();
+ }
+ }
+
+ private void _openLinks(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.UNINITIALIZED);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .allOf(EndpointState.class);
+ for (Link link = conn.linkHead(localState, remoteState); link != null; link = link
+ .next(localState, remoteState)) {
+
+ // configure the link
+ link.setSource(link.getRemoteSource());
+ link.setTarget(link.getRemoteTarget());
+
+ final ProtonClient client = _getClient(link.getSession());
+ client.addLink(link);
+ }
+ }
+
+ private ProtonClient _getClient(Session ssn) {
+ return (ProtonClient) ssn.getContext();
+ }
+
+ private void _openPendingSessions(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.UNINITIALIZED);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .allOf(EndpointState.class);
+
+ for (Session ssn = conn.sessionHead(localState, remoteState); ssn != null; ssn = ssn
+ .next(localState, remoteState)) {
+
+ final ProtonClient client = new ProtonClient(this, ssn);
+ ssn.setContext(client);
+ final Object ctx = connector.getContext();
+ assert (ctx instanceof ProtonAuthenticator);
+ ProtonAuthenticator auth = (ProtonAuthenticator) ctx;
+ if (auth.getAuthType() == AuthenticatorType.SERVER) {
+ ssn.open();
+ final ProtonListener l = (ProtonListener) ctx;
+ l.accept(client);
+ } else {
+ ssn.close();
+ }
+ }
+ }
+
+ private void _initConnection(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ if (conn.getLocalState().equals(EndpointState.UNINITIALIZED)) {
+ conn.open();
+ }
+ }
+
+ private void _acceptConnectionRequests() {
+ for (final Listener<?> l : _driver.listeners()) {
+
+ @SuppressWarnings("unchecked")
+ final Connector<ProtonAuthenticator> connector = (Connector<ProtonAuthenticator>) l
+ .accept();
+ if (connector == null) {
+ continue;
+ }
+ connector.setContext(new ProtonAuthenticator(connector,
+ AuthenticatorType.SERVER));
+ }
+ }
+
+ public void stop() {
+ synchronized (_syncRoot) {
+ _isRunning = false;
+ }
+
+ wakeup();
+ }
+}
\ No newline at end of file
diff --git a/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/AmqpReactorTestHelper.java b/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/AmqpReactorTestHelper.java
new file mode 100644
index 0000000..46d9cc3
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/AmqpReactorTestHelper.java
@@ -0,0 +1,18 @@
+package org.ovirt.vdsm.jsonrpc;
+
+import java.io.IOException;
+import org.ovirt.vdsm.reactors.ProtonReactor;
+import org.ovirt.vdsm.reactors.Reactor;
+
+public class AmqpReactorTestHelper implements ReactorTestHelper {
+ @Override
+ public Reactor createReactor() throws IOException {
+ return new ProtonReactor();
+ }
+
+ @Override
+ public String getUriScheme() {
+ return "amqp";
+ }
+
+}
diff --git a/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/TestJsonRpcClientAMQP.java b/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/TestJsonRpcClientAMQP.java
new file mode 100644
index 0000000..9e0c24c
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/TestJsonRpcClientAMQP.java
@@ -0,0 +1,10 @@
+package org.ovirt.vdsm.jsonrpc;
+
+public class TestJsonRpcClientAMQP extends TestJsonRpcClient {
+
+ @Override
+ protected ReactorTestHelper getHelper() {
+ return new AmqpReactorTestHelper();
+ }
+
+}
--
To view, visit http://gerrit.ovirt.org/15428
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I94c52e118cb63d7df84b89a9b93da7b9e477be91
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years
Change in vdsm[master]: vdsm: expose release call to engine and via vdsClient
by Martin Polednik
Martin Polednik has uploaded a new change for review.
Change subject: vdsm: expose release call to engine and via vdsClient
......................................................................
vdsm: expose release call to engine and via vdsClient
Release would, in ideal world, always be called when VM dies.
Exposing this verbs gives users tool to force release if series
of events lead to situation that should never occur(tm).
Change-Id: I920ae8b5c82134f09a12e56a529fa3d30fd7ab53
Signed-off-by: Martin Polednik <mpolednik(a)redhat.com>
---
M client/vdsClient.py
M vdsm/API.py
M vdsm/rpc/BindingXMLRPC.py
3 files changed, 17 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/94/32394/1
diff --git a/client/vdsClient.py b/client/vdsClient.py
index 783afa6..85d00cd 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -521,6 +521,10 @@
def do_getAllVmStats(self, args):
return self.ExecAndExit(self.s.getAllVmStats())
+ def hostdevRelease(self, args):
+ device_name = args[0]
+ return self.ExecAndExit(self.s.hostdevRelease(device_name))
+
def desktopLogin(self, args):
vmId, domain, user, password = tuple(args[:4])
if len(args) > 4:
@@ -2149,6 +2153,10 @@
('',
'Get Statistics info for all existing VMs'
)),
+ 'hostdevRelease': (serv.do_hostdevRelease,
+ ('<deviceName>',
+ 'Release specified device from any VMs on the host'
+ )),
'getVGList': (serv.getVGList,
('storageType',
'List of all VGs.'
diff --git a/vdsm/API.py b/vdsm/API.py
index 8da6030..6269d72 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -1296,6 +1296,10 @@
devices = hostdev.list_by_caps(self._cif.vmContainer, caps)
return {'status': doneCode, 'deviceList': devices}
+ def hostdevRelease(self, device_name):
+ hostdev.release(device_name)
+ return {'status': doneCode}
+
def getStats(self):
"""
Report host statistics.
diff --git a/vdsm/rpc/BindingXMLRPC.py b/vdsm/rpc/BindingXMLRPC.py
index 4c1ef20..bdd0886 100644
--- a/vdsm/rpc/BindingXMLRPC.py
+++ b/vdsm/rpc/BindingXMLRPC.py
@@ -487,6 +487,10 @@
api = API.Global()
return api.hostdevListByCaps(caps)
+ def hostdevRelease(self, device_name):
+ api = API.Global()
+ return api.hostdevRelease(device_name)
+
def vmGetIoTunePolicy(self, vmId):
vm = API.VM(vmId)
return vm.getIoTunePolicy()
@@ -1004,6 +1008,7 @@
(self.vmGetStats, 'getVmStats'),
(self.getAllVmStats, 'getAllVmStats'),
(self.hostdevListByCaps, 'hostdevListByCaps'),
+ (self.hostdevRelease, 'hostdevRelease'),
(self.vmMigrationCreate, 'migrationCreate'),
(self.vmDesktopLogin, 'desktopLogin'),
(self.vmDesktopLogoff, 'desktopLogoff'),
--
To view, visit http://gerrit.ovirt.org/32394
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I920ae8b5c82134f09a12e56a529fa3d30fd7ab53
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpolednik(a)redhat.com>
8 years, 1 month
Change in vdsm[master]: vdsm hostdev: add support for USB devices
by mpoledni@redhat.com
Martin Polednik has uploaded a new change for review.
Change subject: vdsm hostdev: add support for USB devices
......................................................................
vdsm hostdev: add support for USB devices
Libvirt allows passthrough of USB devices (not busses) - this patch
exposes the functionality in vdsm
Change-Id: Iac74e7537d56bcb940ef07a4654d45cbcdbb1fb0
Signed-off-by: Martin Polednik <mpoledni(a)redhat.com>
---
M vdsm/caps.py
M vdsm/rpc/vdsmapi-schema.json
M vdsm/virt/vm.py
3 files changed, 71 insertions(+), 10 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/54/29054/1
diff --git a/vdsm/caps.py b/vdsm/caps.py
index d937d4e..8c16af6 100644
--- a/vdsm/caps.py
+++ b/vdsm/caps.py
@@ -530,7 +530,12 @@
# back that we could use to uniquely identify and initiate a device
continue
- if capability in ('pci',):
+ if capability in ('pci', 'usb_device'):
+ # Libvirt only allows to attach USB device with capability 'usb',
+ # but the bus identifies itself as 'usb' while device as
+ # 'usb_device'
+ if dev['capability'] == 'usb_device':
+ dev['capability'] = 'usb'
devices.append(dev)
return devices
diff --git a/vdsm/rpc/vdsmapi-schema.json b/vdsm/rpc/vdsmapi-schema.json
index 921f3d4..ac10144 100644
--- a/vdsm/rpc/vdsmapi-schema.json
+++ b/vdsm/rpc/vdsmapi-schema.json
@@ -3156,33 +3156,55 @@
'specParams': 'VmRngDeviceSpecParams'}}
##
+# @StartupPolicy:
+#
+# Possible policies for startup with device
+#
+# @mandatory: fail if missing for any reason (the default)
+#
+# @requisite: fail if missing on boot up, drop if missing
+# on migrate/restore/revert
+#
+# @optional: drop if missing at any start attempt
+#
+# Since: 4.16.0
+##
+{'enum': 'StartupPolicy', 'data': ['mandatory', 'requisite', 'optional']}
+
+##
# @HostDeviceCapability:
#
# Properties of a host device.
#
# @pci: PCI device
#
+# @usb: USB device
+#
# Since: 4.16.0
##
-{'enum': 'HostDeviceCapability', 'data': ['pci']}
+{'enum': 'HostDeviceCapability', 'data': ['pci', 'usb']}
##
# @HostDeviceSpecParams:
#
# Properties of a host device.
#
-# @bootorder: #optional If specified, this device is part of the boot
-# sequence at the specified position
+# @bootorder: #optional If specified, this device is part of the boot
+# sequence at the specified position (for @pci and @usb)
#
-# @bar: #optional ROM visibility in the guest's memory map (for @pci)
+# @bar: #optional ROM visibility in the guest's
+# memory map (for @pci)
#
-# @file: #optional Binary file to be used as device's ROM (for @pci)
+# @file: #optional Binary file to be used as device's ROM (for @pci)
+#
+# @startupPolicy: #optional Possible boot handling with attached device
+# (for @usb)
#
# Since: 4.16.0
##
{'type': 'HostDeviceSpecParams',
- 'data': {'*bootorder': 'int', '*bar': 'bool',
- '*file': 'str'}}
+ 'data': {'*bootorder': 'int', '*bar': 'bool', '*file': 'str',
+ '*startupPolicy': 'StartupPolicy'}}
##
# @HostDevice:
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 6143cfa..6a6978e 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -1631,13 +1631,16 @@
self.log.debug('Detaching hostdev %s', self.name)
self._node.dettach()
- def getPciAddr(self):
+ def _parsecaps(self):
capsxml = _domParseStr(self._node.XMLDesc(0)).childNodes[0]
self.log.debug('Got nodeDevice XML:\n%s',
capsxml.toprettyxml(encoding='utf-8'))
- capsxml = capsxml.getElementsByTagName('capability')[0]
+ return capsxml.getElementsByTagName('capability')[0]
+
+ def getPciAddr(self):
+ capsxml = self._parsecaps()
domain = capsxml.getElementsByTagName('domain')[0]. \
firstChild.nodeValue
bus = capsxml.getElementsByTagName('bus')[0].firstChild.nodeValue
@@ -1646,6 +1649,26 @@
self.log.debug('PCI device %s at address {domain: %s bus: %s '
'slot: %s}', self.name, domain, bus, slot)
return {'domain': domain, 'bus': bus, 'slot': slot}
+
+ def getUsbAddr(self):
+ capsxml = self._parsecaps()
+ addr = {}
+
+ addr['bus'] = capsxml.getElementsByTagName('bus')[0].firstChild. \
+ nodeValue
+ addr['device'] = capsxml.getElementsByTagName('device')[0]. \
+ firstChild.nodeValue
+ # TODO: handle nonexistant product_id and vendor_id by not adding them
+ # to addr
+ addr['product_id'] = capsxml.getElementsByTagName('product')[0].\
+ getAttribute('id')
+ addr['vendor_id'] = capsxml.getElementsByTagName('vendor')[0].\
+ getAttribute('id')
+
+ self.log.debug('USB device %s {product: %s, vendor: %s} at address '
+ '{bus: %s device: %s}', self.name, addr['product_id'],
+ addr['vendor_id'], addr['bus'], addr['device'])
+ return addr
def getXML(self):
"""
@@ -1683,6 +1706,17 @@
rom.setAttrs(**romAttrs)
+ elif self.capability == 'usb_device':
+ addr = self.getPciAddr()
+ try:
+ source.appendChildWithArgs('vendor', None, addr['vendor'])
+ source.appendChildWithArgs('vendor', None, addr['product'])
+ except:
+ source.appendChildWithArgs('address', None, **addr)
+
+ if 'startupPolicy' in self.specParams:
+ source.setAttrs(startupPolicy=self.specParams['startupPolicy'])
+
return hostdev
--
To view, visit http://gerrit.ovirt.org/29054
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iac74e7537d56bcb940ef07a4654d45cbcdbb1fb0
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpoledni(a)redhat.com>
8 years, 1 month
Change in vdsm[master]: vdsm hostdev: add support for SCSI devices
by mpoledni@redhat.com
Martin Polednik has uploaded a new change for review.
Change subject: vdsm hostdev: add support for SCSI devices
......................................................................
vdsm hostdev: add support for SCSI devices
Libvirt allows passthrough of SCSI devices - this patch
exposes the functionality in vdsm
Change-Id: Ia953bcd5eda1b97235a8dd2f5f9593d8f302e5d6
Signed-off-by: Martin Polednik <mpoledni(a)redhat.com>
---
M vdsm/caps.py
M vdsm/rpc/vdsmapi-schema.json
M vdsm/virt/vm.py
3 files changed, 51 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/58/29058/1
diff --git a/vdsm/caps.py b/vdsm/caps.py
index 8c16af6..6112763 100644
--- a/vdsm/caps.py
+++ b/vdsm/caps.py
@@ -530,7 +530,7 @@
# back that we could use to uniquely identify and initiate a device
continue
- if capability in ('pci', 'usb_device'):
+ if capability in ('pci', 'usb_device', 'scsi'):
# Libvirt only allows to attach USB device with capability 'usb',
# but the bus identifies itself as 'usb' while device as
# 'usb_device'
diff --git a/vdsm/rpc/vdsmapi-schema.json b/vdsm/rpc/vdsmapi-schema.json
index ac10144..52f20c1 100644
--- a/vdsm/rpc/vdsmapi-schema.json
+++ b/vdsm/rpc/vdsmapi-schema.json
@@ -3180,9 +3180,11 @@
#
# @usb: USB device
#
+# @scsi: SCSI device
+#
# Since: 4.16.0
##
-{'enum': 'HostDeviceCapability', 'data': ['pci', 'usb']}
+{'enum': 'HostDeviceCapability', 'data': ['pci', 'usb', 'scsi']}
##
# @HostDeviceSpecParams:
@@ -3200,11 +3202,18 @@
# @startupPolicy: #optional Possible boot handling with attached device
# (for @usb)
#
+# @readonly #optional If present, indicates that the device is read
+# only (for @scsi)
+#
+# @shareable #optional If present, this indicates the device is
+# expected to be shared between domains (for @scsi)
+#
# Since: 4.16.0
##
{'type': 'HostDeviceSpecParams',
'data': {'*bootorder': 'int', '*bar': 'bool', '*file': 'str',
- '*startupPolicy': 'StartupPolicy'}}
+ '*startupPolicy': 'StartupPolicy', '*shareable': 'bool',
+ '*readonly*': 'bool'}}
##
# @HostDevice:
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 6a6978e..3cb2eb9 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -1670,6 +1670,33 @@
addr['vendor_id'], addr['bus'], addr['device'])
return addr
+ def getScsiAddr(self):
+ capsxml = self._parsecaps()
+ addr = {}
+
+ addr['type'] = 'scsi'
+ addr['bus'] = capsxml.getElementsByTagName('bus')[0].firstChild. \
+ nodeValue
+ addr['target'] = capsxml.getElementsByTagName('target')[0]. \
+ firstChild.nodeValue
+ addr['unit'] = capsxml.getElementsByTagName('lun')[0]. \
+ firstChild.nodeValue
+
+ self.log.debug('SCSI device %s at address '
+ '{bus: %s, target: %s, unit: %s}',
+ self.name, addr['bus'], addr['target'], addr['unit'],
+ addr['device'])
+ return addr
+
+ def getScsiAdapter(self):
+ capsxml = self._parsecaps()
+
+ adapter = 'scsi_host{}'.format(
+ capsxml.getElementsByTagName('host')[0].firstChild.nodeValue)
+
+ self.log.debug('SCSI device %s adapter %s', self.name, adapter)
+ return adapter
+
def getXML(self):
"""
Create domxml for a hostdev device.
@@ -1717,6 +1744,18 @@
if 'startupPolicy' in self.specParams:
source.setAttrs(startupPolicy=self.specParams['startupPolicy'])
+ elif self.capability == 'scsi':
+ source.appendChildWithArgs('address', None,
+ **self.getScsiHost())
+ source.appendChildWithArgs('adapter', None,
+ **self.getScsiAdapter())
+
+ if 'readonly' in self.specParams:
+ hostdev.appendChild('readonly')
+
+ if 'shareable' in self.specParams:
+ hostdev.appendChild('shareable')
+
return hostdev
--
To view, visit http://gerrit.ovirt.org/29058
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia953bcd5eda1b97235a8dd2f5f9593d8f302e5d6
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpoledni(a)redhat.com>
8 years, 1 month
Change in vdsm[master]: VDSM: implement nodeDeviceMapper
by Martin Polednik
Martin Polednik has uploaded a new change for review.
Change subject: VDSM: implement nodeDeviceMapper
......................................................................
VDSM: implement nodeDeviceMapper
NodeDeviceMapper is structure to keep track of available node devices
and provide easy access to querying and managing them. The mapper
is needed in order to allow VDSM to meaningfully report the usage
of these devices, along with managing their availability.
Change-Id: I6f21d465a90cfe2eb16ba70943e5fcf1683f1656
Signed-off-by: Martin Polednik <mpoledni(a)redhat.com>
---
M client/vdsClient.py
M debian/vdsm.install
M vdsm.spec.in
M vdsm/API.py
M vdsm/clientIF.py
M vdsm/rpc/BindingXMLRPC.py
M vdsm/virt/Makefile.am
7 files changed, 44 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/09/30209/1
diff --git a/client/vdsClient.py b/client/vdsClient.py
index 2c09b28..89dceab 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -461,6 +461,14 @@
def do_getAllVmStats(self, args):
return self.ExecAndExit(self.s.getAllVmStats())
+ def do_getDevicesByCaps(self, args):
+ caps = list(args)
+ return self.ExecAndExit(self.s.getDevicesByCaps(caps))
+
+ def do_getDevicesByDomain(self, args):
+ vmId = args[0]
+ return self.ExecAndExit(self.s.getDevicesByDomain(vmId))
+
def desktopLogin(self, args):
vmId, domain, user, password = tuple(args)
response = self.s.desktopLogin(vmId, domain, user, password)
@@ -2077,6 +2085,16 @@
('',
'Get Statistics info for all existing VMs'
)),
+ 'getDevicesByCaps': (serv.do_getDevicesByCaps,
+ ('[<caps>]',
+ 'Get available node devices on the host with '
+ 'given capability'
+ )),
+ 'getDevicesByDomain': (serv.do_getDevicesByDomain,
+ ('<vmId>',
+ 'Get available node devices attached to specified '
+ 'domain'
+ )),
'getVGList': (serv.getVGList,
('storageType',
'List of all VGs.'
diff --git a/debian/vdsm.install b/debian/vdsm.install
index 3af1100..e1d8652 100644
--- a/debian/vdsm.install
+++ b/debian/vdsm.install
@@ -142,6 +142,7 @@
./usr/share/vdsm/virt/__init__.py
./usr/share/vdsm/virt/guestagent.py
./usr/share/vdsm/virt/migration.py
+./usr/share/vdsm/virt/nodedev.py
./usr/share/vdsm/virt/sampling.py
./usr/share/vdsm/virt/vm.py
./usr/share/vdsm/virt/vmchannels.py
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 16b7834..0ddacbe 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -939,6 +939,7 @@
%{_datadir}/%{vdsm_name}/virt/__init__.py*
%{_datadir}/%{vdsm_name}/virt/guestagent.py*
%{_datadir}/%{vdsm_name}/virt/migration.py*
+%{_datadir}/%{vdsm_name}/virt/nodedev.py*
%{_datadir}/%{vdsm_name}/virt/vmchannels.py*
%{_datadir}/%{vdsm_name}/virt/vmstatus.py*
%{_datadir}/%{vdsm_name}/virt/vmtune.py*
diff --git a/vdsm/API.py b/vdsm/API.py
index 6feccf6..e891b80 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -1244,6 +1244,18 @@
statsList = hooks.after_get_all_vm_stats(statsList)
return {'status': doneCode, 'statsList': statsList}
+ def getDevicesByCaps(self, caps):
+ """
+ """
+ devices = self._cif.nodeDeviceMapper.getDevicesByCaps(caps)
+ return {'status': doneCode, 'devices': devices}
+
+ def getDevicesByDomain(self, vmId):
+ """
+ """
+ devices = self._cif.nodeDeviceMapper.getDevicesByDomain(vmId)
+ return {'status': doneCode, 'devices': devices}
+
def getStats(self):
"""
Report host statistics.
diff --git a/vdsm/clientIF.py b/vdsm/clientIF.py
index d5372f3..118652d 100644
--- a/vdsm/clientIF.py
+++ b/vdsm/clientIF.py
@@ -91,6 +91,7 @@
self.gluster = None
try:
self.vmContainer = {}
+ self.nodeDeviceMapper = NodeDeviceMapper(vmContainer, log)
self._hostStats = sampling.HostStatsThread(log=log)
self._hostStats.start()
self.lastRemoteAccess = 0
diff --git a/vdsm/rpc/BindingXMLRPC.py b/vdsm/rpc/BindingXMLRPC.py
index d6663c3..a31d76c 100644
--- a/vdsm/rpc/BindingXMLRPC.py
+++ b/vdsm/rpc/BindingXMLRPC.py
@@ -482,6 +482,14 @@
api = API.Global()
return api.getAllVmStats()
+ def getDevicesByCaps(self, caps):
+ api = API.Global()
+ return api.getDevicesByCaps(caps)
+
+ def getDevicesByDomain(self, vmId):
+ api = API.Global()
+ return api.getDevicesByDomain(vmId)
+
def vmGetIoTunePolicy(self, vmId):
vm = API.VM(vmId)
return vm.getIoTunePolicy()
@@ -989,6 +997,8 @@
(self.getStats, 'getVdsStats'),
(self.vmGetStats, 'getVmStats'),
(self.getAllVmStats, 'getAllVmStats'),
+ (self.getDevicesByCaps, 'getDevicesByCaps'),
+ (self.getDevicesByDomain, 'getDevicesByDomain'),
(self.vmMigrationCreate, 'migrationCreate'),
(self.vmDesktopLogin, 'desktopLogin'),
(self.vmDesktopLogoff, 'desktopLogoff'),
diff --git a/vdsm/virt/Makefile.am b/vdsm/virt/Makefile.am
index 423839b..4b7b1cc 100644
--- a/vdsm/virt/Makefile.am
+++ b/vdsm/virt/Makefile.am
@@ -25,6 +25,7 @@
__init__.py \
guestagent.py \
migration.py \
+ nodedev.py \
sampling.py \
vm.py \
vmchannels.py \
--
To view, visit http://gerrit.ovirt.org/30209
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6f21d465a90cfe2eb16ba70943e5fcf1683f1656
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpolednik(a)redhat.com>
8 years, 1 month
Change in vdsm[master]: [WIP] vdsm: add support for PCI passthrough
by mpoledni@redhat.com
Martin Polednik has uploaded a new change for review.
Change subject: [WIP] vdsm: add support for PCI passthrough
......................................................................
[WIP] vdsm: add support for PCI passthrough
required functionality:
* report PCI devices available on host [x]
* handle createVm xml generation [x]
* hotplugHostdev [ ] (required for after-migration)
* hotpunlugHostdev [ ] (required for migration)
Change-Id: I363d2622d72ca2db75f60032fe0892c348bab121
Signed-off-by: Martin Polednik <mpoledni(a)redhat.com>
---
M lib/vdsm/define.py
M vdsm/caps.py
M vdsm/vm.py
3 files changed, 83 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/62/22462/1
diff --git a/lib/vdsm/define.py b/lib/vdsm/define.py
index eb78633..9605f93 100644
--- a/lib/vdsm/define.py
+++ b/lib/vdsm/define.py
@@ -132,6 +132,12 @@
'transientErr': {'status': {
'code': 59,
'message': 'Action not permitted on a VM with transient disks'}},
+ 'hotplugHostdev': {'status': {
+ 'code': 60,
+ 'message': 'Failed to hotplug hostdev'}},
+ 'hotunplugHostdev': {'status': {
+ 'code': 61,
+ 'message': 'Failed to hotunplug hostdev'}},
'recovery': {'status': {
'code': 99,
'message': 'Recovering from crash or Initializing'}},
diff --git a/vdsm/caps.py b/vdsm/caps.py
index 3839134..d6af375 100644
--- a/vdsm/caps.py
+++ b/vdsm/caps.py
@@ -308,6 +308,38 @@
return dict(release=release, version=version, name=osname)
+def hostdevList():
+ devices = []
+ for device in libvirtconnection.get().listAllDevices():
+ devXML = minidom.parseString(device.XMLDesc())
+ dev = {}
+
+ # we have to grab attributes that will most likely not only
+ # uniquely identify device, but also serve as human readable
+ # representation of the device
+ try:
+ dev['name'] = devXML.getElementsByTagName('name')[0].\
+ childNodes[0].data
+ capability = devXML.getElementsByTagName('capability')[0]
+ try:
+ dev['product'] = capability.getElementsByTagName('product')[0]\
+ .childNodes[0].data
+ dev['vendor'] = capability.getElementsByTagName('vendor')[0].\
+ childNodes[0].data
+ except IndexError:
+ # althought the retrieval of product/vendor was not successful,
+ # we can still report back the name
+ pass
+ except IndexError:
+ # should device not have a name, there is nothing engine could send
+ # back that we could use to uniquely identify and initiate a device
+ continue
+
+ devices.append(dev)
+
+ return devices
+
+
def get():
targetArch = platform.machine()
@@ -360,6 +392,7 @@
config.getint('vars', 'extra_mem_reserve'))
caps['guestOverhead'] = config.get('vars', 'guest_ram_overhead')
caps['rngSources'] = _getRngSources()
+ caps['hostDevices'] = hostdevList()
return caps
diff --git a/vdsm/vm.py b/vdsm/vm.py
index a5d923b..a477bc9 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -78,6 +78,7 @@
WATCHDOG_DEVICES = 'watchdog'
CONSOLE_DEVICES = 'console'
SMARTCARD_DEVICES = 'smartcard'
+HOSTDEV_DEVICES = 'hostdev'
def isVdsmImage(drive):
@@ -1656,6 +1657,27 @@
return m
+class HostDevice(VmDevice):
+ def getXML(self):
+ """
+ Create domxml for a hostdev device.
+
+ <devices>
+ <hostdev mode='subsystem' type='usb'>
+ <source startupPolicy='optional'>
+ <vendor id='0x1234'/>
+ <product id='0xbeef'/>
+ </source>
+ <boot order='2'/>
+ </hostdev>
+ </devices>
+ """
+ # libvirt gives us direct api call to construct the XML
+ return xml.dom.minidom.parseString(libvirtconnection.get().
+ nodeDeviceLookupByName(self.name).
+ XMLDesc())
+
+
class WatchdogDevice(VmDevice):
def __init__(self, *args, **kwargs):
super(WatchdogDevice, self).__init__(*args, **kwargs)
@@ -1769,7 +1791,8 @@
(CONSOLE_DEVICES, ConsoleDevice),
(REDIR_DEVICES, RedirDevice),
(RNG_DEVICES, RngDevice),
- (SMARTCARD_DEVICES, SmartCardDevice))
+ (SMARTCARD_DEVICES, SmartCardDevice),
+ (HOSTDEV_DEVICES, HostDevice))
def _makeDeviceDict(self):
return dict((dev, []) for dev, _ in self.DeviceMapping)
@@ -3127,6 +3150,26 @@
break
+ def hotplugHostdev(self, params):
+ hostdev = HostDevice(self.conf, self.log, **params)
+ self._devices[HOSTDEV_DEVICES].append(hostdev)
+ hostdevXML = hostdev.getXML().toprettyxml(encoding='utf-8')
+ hostdev._deviceXML = hostdevXML
+ self.log.debug("Hotplug hostdev xml: %s", hostdevXML)
+
+ try:
+ self._dom.attachDevice(hostdevXML)
+ except libvirt.libvirtError as e:
+ self.log.error("Hotplug failed", exc_info=True)
+ if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
+ return errCode['noVM']
+ return {'status': {'code':
+ errCode['hotplugHostdev']['status']['code'],
+ 'message': e.message}}
+
+ def hotunplugHostdev(self, name):
+ pass
+
def hotplugNic(self, params):
if self.isMigrating():
return errCode['migInProgress']
--
To view, visit http://gerrit.ovirt.org/22462
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I363d2622d72ca2db75f60032fe0892c348bab121
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpoledni(a)redhat.com>
8 years, 1 month
Change in vdsm[master]: netinfo: improve which ipv4 addr is reported if there are mu...
by asegurap@redhat.com
Antoni Segura Puimedon has uploaded a new change for review.
Change subject: netinfo: improve which ipv4 addr is reported if there are multiple primary
......................................................................
netinfo: improve which ipv4 addr is reported if there are multiple primary
The current code assumed that additional configured addresses for a
device would have the 'secondary' flag. However, this is no longer
true in recent kernels, as multiple primary addresses can be set for
a device.
The improvement is that now we will check if any of the addresses is
in the subnet of the gateway and report one of them. If there is no
default gw in the main table for the device we return the last
set primary ip and if there is a default gw but going through another
hop, we return the first set ip.
Change-Id: I8666cfef5bd8ea63edf8979e501d4785db5f4893
Signed-off-by: Antoni S. Puimedon <asegurap(a)redhat.com>
---
M lib/vdsm/netinfo.py
1 file changed, 35 insertions(+), 7 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/75/33375/1
diff --git a/lib/vdsm/netinfo.py b/lib/vdsm/netinfo.py
index 6491505..816810d 100644
--- a/lib/vdsm/netinfo.py
+++ b/lib/vdsm/netinfo.py
@@ -292,25 +292,49 @@
struct.pack("!I", int('1' * prefix + '0' * (32 - prefix), 2)))
+def prefix2int(prefix):
+ if not 0 <= prefix <= 32:
+ raise ValueError('%s is not a valid prefix value. It must be between '
+ '0 and 32')
+ return (2 ** prefix - 1) << (32 - prefix)
+
+
+def addr2int(address):
+ return struct.unpack('!I', socket.inet_aton(address))[0]
+
+
def getDefaultGateway():
output = routeShowGateways('main')
return Route.fromText(output[0]) if output else None
-def getIpInfo(dev, ipaddrs=None):
+def getIpInfo(dev, ipaddrs=None, ipv4_gateway=None):
if ipaddrs is None:
ipaddrs = _getIpAddrs()
ipv4addr = ipv4netmask = ''
ipv4addrs = []
ipv6addrs = []
+ gateway_int = addr2int(ipv4_gateway) if ipv4_gateway else None
+
for addr in ipaddrs[dev]:
if addr['family'] == 'inet':
ipv4addrs.append(addr['address'])
if 'secondary' not in addr['flags']:
- ipv4addr, prefix = addr['address'].split('/')
- ipv4netmask = prefix2netmask(addr['prefixlen'])
+ address, _ = addr['address'].split('/')
+ mask = prefix2int(addr['prefixlen'])
+ if (gateway_int is None or
+ addr2int(address) & mask == gateway_int & mask):
+ ipv4addr = address
+ ipv4netmask = prefix2netmask(addr['prefixlen'])
else:
ipv6addrs.append(addr['address'])
+ if ipv4addrs and ipv4addr == '':
+ # If we didn't find an address in the gateway subnet (which is
+ # legal if there is another route that takes us to the gateway) we
+ # choose to report the first address
+ ipv4addr, prefix = ipv4addrs[0].split('/')
+ ipv4netmask = prefix2netmask(int(prefix))
+
return ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs
@@ -501,14 +525,16 @@
# comment when the version is no longer supported.
data['interface'] = iface
- ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(iface, ipaddrs)
+ gateway = _get_gateway(routes, iface)
+ ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(
+ iface, ipaddrs, gateway)
data.update({'iface': iface, 'bridged': bridged,
'addr': ipv4addr, 'netmask': ipv4netmask,
'bootproto4': ('dhcp' if ipv4addr and iface in dhcp4
else 'none'),
'ipv4addrs': ipv4addrs,
'ipv6addrs': ipv6addrs,
- 'gateway': _get_gateway(routes, iface),
+ 'gateway': gateway,
'ipv6gateway': _get_gateway(routes, iface, family=6),
'mtu': str(getMtu(iface))})
except (IOError, OSError) as e:
@@ -549,12 +575,14 @@
def _devinfo(link, routes, ipaddrs, dhcp4):
- ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(link.name, ipaddrs)
+ gateway = _get_gateway(routes, link.name)
+ ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(
+ link.name, ipaddrs, gateway)
info = {'addr': ipv4addr,
'cfg': getIfaceCfg(link.name),
'ipv4addrs': ipv4addrs,
'ipv6addrs': ipv6addrs,
- 'gateway': _get_gateway(routes, link.name),
+ 'gateway': gateway,
'ipv6gateway': _get_gateway(routes, link.name, family=6),
'bootproto4': ('dhcp' if ipv4addr and link.name in dhcp4
else 'none'),
--
To view, visit http://gerrit.ovirt.org/33375
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8666cfef5bd8ea63edf8979e501d4785db5f4893
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>
8 years, 1 month
Change in vdsm[master]: vm: make acpiShutdown more robust
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: vm: make acpiShutdown more robust
......................................................................
vm: make acpiShutdown more robust
In the Vm shutdown flow, the actual 'destruction'
of the domain -in libvirt jargon- may already happen
asynchonously, e.g. if QEMU dies suddenly.
Moreover, we want to make it asynchronously even on
our own code for performance reasons.
This means that the Vm._dom attribute may become None
asyncrhonously, even inside the Vm powerdown flow
itself.
This patch address the case for the acpiShutdown,
fixing this issue:
Thread-259072::ERROR::2014-10-15 12:06:52,842::utils::1193::utils.Callback::(__call__) acpiCallback failed
Traceback (most recent call last):
File "/usr/lib64/python2.6/site-packages/vdsm/utils.py", line 1191, in __call__
result = self.func(*self.args, **self.kwargs)
File "/usr/share/vdsm/virt/vmpowerdown.py", line 91, in acpiCallback
self.vm.acpiShutdown()
File "/usr/share/vdsm/virt/vm.py", line 4942, in acpiShutdown
self._dom.shutdownFlags(libvirt.VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN)
AttributeError: 'NoneType' object has no attribute 'shutdownFlags'
Change-Id: I244f00d62ee24fb42ba3d654961a8fc22f4a6c25
Related-To: https://bugzilla.redhat.com/show_bug.cgi?id=1154389
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M vdsm/virt/vm.py
1 file changed, 7 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/79/34879/1
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 9740ab3..2384aca 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -4402,7 +4402,13 @@
def acpiShutdown(self):
self._shutdownReason = vmexitreason.ADMIN_SHUTDOWN
- self._dom.shutdownFlags(libvirt.VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN)
+ try:
+ self._dom.shutdownFlags(libvirt.VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN)
+ except AttributeError:
+ if not self._released:
+ raise
+ # else the VM was already shut off asynchronously,
+ # so ignore error and quickly exit
def setBalloonTarget(self, target):
--
To view, visit http://gerrit.ovirt.org/34879
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I244f00d62ee24fb42ba3d654961a8fc22f4a6c25
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
8 years, 1 month