How to "start" or "activate" a network with libvirt? - libvirt

How do you "start" an inactive network using libvirt? With virsh this would be net-start <network>.
I can create a network with virNetworkDefineXML, which will:
Define an inactive persistent virtual network or modify an existing persistent one from the XML description.
(which is the equivalent of virsh net-define), but I don't know how to "start" this newly-created, but inactive network.
I'm using the libvirt-python bindings, but knowing the correct C API would be sufficient.

The API is virNetworkCreate():
Create and start a defined network. If the call succeed the network moves from the defined to the running networks pools.
To find this, we can look at the source for virsh. The "net-start" command is defined in tools/virsh-network.c:
static bool
cmdNetworkStart(vshControl *ctl, const vshCmd *cmd)
{
virNetworkPtr network;
bool ret = true;
const char *name = NULL;
if (!(network = virshCommandOptNetwork(ctl, cmd, &name)))
return false;
if (virNetworkCreate(network) == 0) {
vshPrint(ctl, _("Network %s started\n"), name);
} else {
vshError(ctl, _("Failed to start network %s"), name);
ret = false;
}
virNetworkFree(network);
return ret;
}
In libvirt-python, this means simply calling .create() on the network object returned from .networkDefineXML():
conn = libvirt.open('qemu:///system')
# Define a new persistent, inactive network
xml = open('net.xml', 'r').read()
net = conn.networkDefineXML(xml)
# Set it to auto-start
net.setAutostart(True)
# Start it!
net.create()

Related

Create a Network Load Balancer on Oracle Cloud Infrastructure with a Reserved IP using Terraform

Using Terraform to set up a Network Load Balancer on Oracle Cloud Infrastructure, it works as expected if created with an ephemeral public IP, however one created using a reserved public IP does not respond. Here are the exact Terraform resourses used to create the load balancer:
resource "oci_core_public_ip" "ip" {
for_each = { for lb in var.load_balancers: lb.subnet => lb if ! lb.private
compartment_id = local.compartment_ocid
display_name = "${var.name}-public-ip"
lifetime = "RESERVED"
lifecycle {
prevent_destroy = true
}
}
resource "oci_network_load_balancer_network_load_balancer" "nlb" {
for_each = { for lb in var.load_balancers: lb.subnet => lb if lb.type == "network" }
compartment_id = local.compartment_ocid
display_name = "${var.name}-network-load-balancer"
subnet_id = oci_core_subnet.s[each.value.subnet].id
is_private = each.value.private
#reserved_ips {
# id = oci_core_public_ip.ip[each.value.subnet].id
#}
}
All of the other resources: security list rules, listeners, backend set and backends, etc, etc, are created such that the above works. If, however I uncomment the assignment of reserved_ips to the network load balancer then it does not work: no response from the load balancer's public IP. Everything is the same except those three lines being uncommented.
Between each test I tear down everything and recreate with Terraform. It always works with an ephemeral IP and never works with the reserved IP. Why? What am I missing? Or does this just not work as advertised?
The Terraform version is v1.3.4 and the resource version is oracle/oci version 4.98.0.
The reserved IP is set up correctly however the terraform provider removes its association with the load balancer's private IP. Closer inspection of the Terraform output shows this
~ resource "oci_core_public_ip" "ip" {
id = "ocid1.publicip.oc1.uk-london-1.ama...sta"
- private_ip_id = "ocid1.privateip.oc1.uk-london-1.abw...kya" -> null
# (11 unchanged attributes hidden)
}
Manually replacing it fixes it (until the next tf run)
$ oci network public-ip update --public-ip-id ocid1.publicip.oc1.uk-london-1.ama...rrq --private-ip-id ocid1.privateip.oc1.uk-london-1.abw...kya
There is a bug ticket on Terraform's github.

SSH to Google Compute instance using NodeJS, without gcloud

I'm trying to create a SSH tunnel into a compute instance, from an environment that doesn't have gcloud installed (App Engine Standard NodeJS Environment).
What are the steps needed to do that? How does gcloud compute ssh command does it? Is there a NodeJS library that already does it?
I created the package gcloud-ssh-tunnel that does the necessary steps:
Create a private/public key using sshpk
Imports the public key using the OS Login API
SSH using ssh2 (and specifically create a tunnel, because this was the use case I needed - see the Why? section in the package)
Delete the public key using the OS Login API (to not overflow the account or leave security access)
You can use ssh2 to do that in nodejs.
"gcloud compute ssh" generates persistent SSH keys for the user. The public key is stored in project or instance SSH keys metadata, and the Guest Environment creates the necessary local user and places ~/.ssh/authorized_keys in its home directory.
You can manually add your public key to the instance, and then connect to it via ssh using a node ssh library1.
Or you can set a startup script for the instance when you are creating it2.
As Cloud Ace pointed out, you can use the ssh2 module3 for node.js compatibility.
In order to SSH into a GCP instance you have to:
Enable OS Login
Create a service account and assign it "Compute OS Admin Login" role.
Create SSH key and import it into the service account.
Use that SSH key and POSIX username.
The first 2 steps already link to the documentation.
Create SSH key:
import {
generatePrivateKey,
} from 'sshpk';
const keyPair = generatePrivateKey('ecdsa');
const privateKey = keyPair.toString();
const publicKey = keyPair.toPublic().toString();
Import key:
const osLoginServiceClient = new OsLoginServiceClient({
credentials: googleCredentials,
});
const [result] = await osLoginServiceClient.importSshPublicKey({
parent: osLoginServiceClient.userPath(googleCredentials.client_email),
sshPublicKey: {
expirationTimeUsec: ((Date.now() + 10 * 60 * 1_000) * 1_000).toString(),
key: publicKey,
},
});
SSH using the key:
const ssh = new NodeSSH();
await ssh.connect({
host,
privateKey,
username: loginProfile.posixAccounts[0].username,
});
In this example, I am using node-ssh but you can use anything.
The only other catch is that you need to figure out the public host. Implementation for that looks like this:
const findFirstPublicIp = async (
googleCredentials: GoogleCredentials,
googleZone: string,
googleProjectId: string,
instanceName: string,
) => {
const instancesClient = new InstancesClient({
credentials: googleCredentials,
});
const instances = await instancesClient.get({
instance: instanceName,
project: googleProjectId,
zone: googleZone,
});
for (const instance of instances) {
if (!instance || !('networkInterfaces' in instance) || !instance.networkInterfaces) {
throw new Error('Unexpected result.');
}
for (const networkInterface of instance.networkInterfaces) {
if (!networkInterface || !('accessConfigs' in networkInterface) || !networkInterface.accessConfigs) {
throw new Error('Unexpected result.');
}
for (const accessConfig of networkInterface.accessConfigs) {
if (accessConfig.natIP) {
return accessConfig.natIP;
}
}
}
}
throw new Error('Could not locate public instance IP address.');
};
Finally, to clean up, you have to call deleteSshPublicKey with the name of the key that you've imported:
const fingerprint = crypto
.createHash('sha256')
.update(publicKey)
.digest('hex');
const sshPublicKey = loginProfile.sshPublicKeys?.[fingerprint];
if (!sshPublicKey) {
throw new Error('Could not locate SSH public key with a matching fingerprint.');
}
const ssh = new NodeSSH();
await ssh.connect({
host,
privateKey,
username: loginProfile.posixAccounts[0].username,
});
await osLoginServiceClient.deleteSshPublicKey({
name: sshPublicKey.name,
});
In general, you'd need to reserve & assign a static external IP address to begin with (unless trying to SSH from within the same network). And a firewall rule needs to be defined for port tcp/22, which then can be applied as a "label" to the network interface, which has that external IP assigned.
The other way around works with gcloud app instances ssh:
SSH into the VM of an App Engine Flexible instance
which might be less effort & cost to setup, because a GCP VM usually has gcloud installed.

How to handle Modbus exception 0x5

I'm writing a Modbus client program using Qt5 and the QModbusTcpClient class. Here the code I'm using for open a connection and read something:
QModbusClient *_modbus;
bool ModbusMaster::open(QString host, int port)
{
// Disconnect and delete any existing instance
if (_modbus)
{
_modbus->disconnectDevice();
delete _modbus;
}
// Create and open the new connection
_modbus = new QModbusTcpClient(this);
_modbus->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
_modbus->setConnectionParameter(QModbusDevice::NetworkAddressParameter, host);
_modbus->setTimeout(250);
_modbus->setNumberOfRetries(1);
return _modbus->connectDevice();
}
bool ModbusMaster::read(QModbusDataUnit::RegisterType type, int startAddress, quint16 count)
{
if (!_modbus) return false;
if (_modbus->state() != QModbusDevice::ConnectedState) return false;
QModbusDataUnit req(type, startAddress, count);
if (auto *reply = _modbus->sendReadRequest(req, _id))
{
if (!reply->isFinished()) connect(reply, &QModbusReply::finished, this, &ModbusMaster::readReady);
else delete reply;
return true;
}
return false;
}
void ModbusMaster::readReady()
{
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply) return;
reply->deleteLater();
if (reply->error() == QModbusDevice::NoError)
{
// do something
}
else if (reply->error() == QModbusDevice::ProtocolError)
{
qDebug() << QString("Read response error: %1 (Mobus exception: 0x%2)").
arg(reply->errorString()).
arg(reply->rawResult().exceptionCode(), -1, 16);
} else {
qDebug() << QString("Read response error: %1 (code: 0x%2)").
arg(reply->errorString()).
arg(reply->error(), -1, 16);
}
}
Sometimes when I read something from the remote device it happens the device returns the exception 0x5. Reading the official Modbus documentation, at page 48 I read:
Specialized use in conjunction with programming
commands.
The server has accepted the request and is
processing it, but a long duration of time will be
required to do so. This response is returned to
prevent a timeout error from occurring in the
client. The client can next issue a Poll Program
Complete message to determine if processing is
completed.
[bold is mine]
I cannot find a description of this "Poll Program Complete message" that seems I must use to handle the exception 0x5.
Did I search wrong? Is there another way to handle this exception?
It depends on type of an equipment, you are working with. You just have to follow the logic, described in equipment mans for this particular exception.
In general there is no special 'Program Complete' event. That means, as it is written for 0x5 - "Specialized use in conjunction with programming commands.". So you just have to poll (read) some flag from your device meaning the internal process in device, which caused this exception, is complete.
Just as an example, I've met with such exception in relay protection device, which issued it when it has been in a process of writing a disturbance record. I had just to check for that record readiness in some time.

Can't connect to MySQL/MariaDB database from vibed app

All work fine if I use custom main ( void main() instead of shared static this() ).
With default main I am getting "Access Violation" error. It's look like MySQL not allow connecting to it from localhost, but in my.ini I added string:
bind-address = 127.0.0.1
code, if it's help:
import std.stdio;
import std.path;
import std.file;
import std.string;
import dini;
import vibe.d;
import colorize;
import ddbc.all;
shared static this()
{
auto settings = new HTTPServerSettings;
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
listenHTTP(settings, &hello);
auto parseconfig = new ParseConfig();
auto db = new DBConnect(parseconfig);
}
void hello(HTTPServerRequest req, HTTPServerResponse res)
{
res.writeBody("Hello, World!");
}
class ParseConfig
{
string dbname;
string dbuser;
string dbpass;
string dbhost;
string dbport;
this()
{
try
{
//getcwd do not return correct path if run from task shoulder
string confpath = buildPath((thisExePath[0..((thisExePath.lastIndexOf("\\"))+1)]), "config.ini");
//writefln(thisExePath[0..((thisExePath.lastIndexOf("\\"))+1)]); // get path without extention +1 is for getting last slash
//string confpath = buildPath(thisExePath, "config.ini");
if (!exists(confpath))
{
writeln("ERROR: config.ini do not exists");
}
auto config = Ini.Parse(confpath);
try
{
this.dbname = config.getKey("dbname");
this.dbuser = config.getKey("dbuser");
this.dbpass = config.getKey("dbpass");
this.dbhost = config.getKey("dbhost");
this.dbport = config.getKey("dbport");
}
catch (Exception msg)
{
cwritefln("ERROR: Can't parse config: %s".color(fg.red), msg.msg);
}
}
catch(Exception msg)
{
cwriteln(msg.msg.color(fg.red));
core.thread.Thread.sleep( dur!("msecs")(1000));
}
}
}
class DBConnect
{
Statement stmt;
ParseConfig parseconfig;
this(ParseConfig parseconfig)
{
try
{
this.parseconfig = parseconfig;
MySQLDriver driver = new MySQLDriver();
string url = MySQLDriver.generateUrl(parseconfig.dbhost, to!short(parseconfig.dbport), parseconfig.dbname);
string[string] params = MySQLDriver.setUserAndPassword(parseconfig.dbuser, parseconfig.dbpass);
DataSource ds = new ConnectionPoolDataSourceImpl(driver, url, params);
auto conn = ds.getConnection();
scope(exit) conn.close();
stmt = conn.createStatement();
writefln("\n[Database connection OK]");
}
catch (Exception ex)
{
writefln(ex.msg);
writeln("Could not connect to DB. Please check settings");
}
}
}
Also I run next command:
GRANT ALL PRIVILEGES ON *.* TO 'root'#'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH PRIVILEGES;
also I tried different bind-address like: 0.0.0.0 and localhost but without result. After every new binding I did restart of MySQL service.
I am using this driver http://code.dlang.org/packages/ddbc
What's wrong?
To continue on my comment ( Can't connect to MySQL/MariaDB database from vibed app ).
I just tested, and it's definitely the event loop ;)
Instead of:
auto parseconfig = new ParseConfig();
auto db = new DBConnect(parseconfig);
Just do:
runTask({
auto parseconfig = new ParseConfig();
auto db = new DBConnect(parseconfig);
});
Worked for me (DMD 2.067.0 / Vibe 0.7.23 / ddbc 0.2.24 / colorize & dini master).
To answer your comment ( Can't connect to MySQL/MariaDB database from vibed app) : the event loop starts inside the main function.
What happens when you launch a D application ? The entry point is a C main inside the runtime, which initialize it (the runtime), including module constructor, run the unittest (if you've compiled with -unittest), then call your main (which name is "_Dmain" - useful to know if you want to set a breakpoint with GDB).
When Vibe.d's main is called, it parses command line argument, an optional config file, and finally, starts the event loop. Any code that wish to run once the event loop has started should use runTask and similar, or createTimer. They should not call the code directly from the static constructor (it's actually one of the most common mistake when starting with Vibe.d).
I ran into an issue that could be related while developing mysql-lited, an alternative MySQL/MariaDB driver.
The issue I think is related to a module initialization order bug in phobos/SHA1, which I believe is still open in 2.067.1. The suggested work-around is to use VibeCustomMain instead, and define your own main(). You can just copy the defaul main() from appmain.d and use that.
Alternatively you could try mysql-lited and see if that works better for you.

Windows phone 8 - IP address is of wifi or carrier

I am developing an application on windows phone 8, and would like to know - Is it possible to check whether retrieved device IP address is over Wifi or carrier?
Code used to find device IP address is -
public IPAddress IdentifyDeviceIp()
{
List<string> DeviceIPAddresses = new List<string>();
var DeviceHostnames = Windows.Networking.Connectivity.NetworkInformation.GetHostNames();
foreach (var DeviceHostName in DeviceHostnames)
{
if (DeviceHostName.IPInformation != null)
{
string DeviceIpAddress = DeviceHostName.DisplayName;
// Emulator: ignore IPV6 addresses
if (DeviceIpAddress.Contains(":"))
continue;
DeviceIPAddresses.Add(DeviceIpAddress);
}
}
if (DeviceIPAddresses.Count == 0)
{
MessageBox.Show("No IP address found!!");
return new IPAddress(0);
}
return IPAddress.Parse(DeviceIPAddresses[0]);
}
To determine what a network is currently used by a phone you can check NetworkInterfaceType. Mode details here http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh487166(v=vs.105).aspx.
you can use this code for determinate where is the type of Network Interface :
NetworkInterfaceType MyNetworkInterfaceType = Microsoft.Phone.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType;
If you've on Wifi, this code return "Wireless80211", you can read all documentation here
Also, with Windows Phone, you can Set your prefer NetworkInterface ( If you hove connected on Wifi and, on 3G, you can create a request with the Cellular connection (2G/3G/4G) or with NonCellular connection ( Ethernet, Wifi...) you can read this for information
You can Set your prefer Network for SocketRequest and for WebRequest you can read documentation about that in the msdn :
Microsoft.Phone.Net.NetworkInformation.WebRequestExtensions
Microsoft.Phone.Net.NetworkInformation.SocketExtensions
Use just the function
SetNetworkPreference(Socket/WebRequest, NetworkSelectionCharacteristics)
for define a request with your prefer network.
For better Experience for your application user, prefer the NonCellular DataConnection, generaly, it's faster [except for 4G] and cheaper... :D
For Your Problem, If you Set your prefer Connection, and you send a request, the ip adress use for this request must match the network defined preference.