Skip to content
Snippets Groups Projects
Commit 06006a76 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Merge branch 'develop' of ssh://gifrerenom_labs.etsi.org/tfs/controller into...

Merge branch 'develop' of ssh://gifrerenom_labs.etsi.org/tfs/controller into feat/130-opt-sbi-for-qkd-nodes
parents b860662c 4d16becb
Branches
Tags
2 merge requests!294Release TeraFlowSDN 4.0,!262Resolve "(OPT) SBI for QKD Nodes", "(OPT) QKD Network Topology" and "(OPT) Path Computation for QKD Networks"
Showing
with 1722 additions and 3 deletions
{
"name": "dlt_gateway",
"version": "1.0.0",
"description": "A DLT application that record and manages network related data as JSON, implemented in typeScript using HLF fabric-gateway",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"engines": {
"node": ">=18"
},
"scripts": {
"build": "tsc",
"build:watch": "tsc -w",
"lint": "eslint . --ext .ts",
"prepare": "npm run build",
"pretest": "npm run lint",
"start": "node dist/dlt_gateway.js"
},
"engineStrict": true,
"author": "Javier Jose Diaz (CTTC)",
"license": "Apache-2.0",
"dependencies": {
"@grpc/grpc-js": "^1.10.8",
"@grpc/proto-loader": "^0.7.13",
"@hyperledger/fabric-gateway": "~1.4.0",
"dotenv": "^16.4.5",
"grpc-tools": "^1.12.4",
"protobufjs": "^7.3.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@tsconfig/node18": "^18.2.2",
"@types/node": "^18.18.6",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.9.0",
"eslint": "^8.52.0",
"typescript": "~5.2.2"
}
}
// Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const path = require('path');
const { connectToNetwork } = require('../dist/fabricConnect');
const utf8Decoder = new TextDecoder();
// Load the protocol buffer definitions
const PROTO_PATH = path.resolve(__dirname, '../proto/dlt_gateway.proto');
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const dltProto = grpc.loadPackageDefinition(packageDefinition).dlt;
// Create a gRPC server instance
const server = new grpc.Server();
let contractInstance = null;
let closeConnection = null;
let events = null; // To store the events iterable
const clients = new Set(); // Set to keep track of active client streams
// Initialize connection to the chaincode
async function initChaincodeConnection() {
try {
const networkResources = await connectToNetwork();
contractInstance = networkResources.contract;
events = networkResources.events; // Initiate event listening
closeConnection = networkResources.close;
//console.log("DEBUG", events)
console.log("Chaincode connection established successfully.");
} catch (error) {
console.error('Failed to establish chaincode connection:', error);
process.exit(1); // Exit if the connection cannot be established
}
}
// gRPC method to handle recording data to the DLT
async function recordToDlt(call, callback) {
if (!contractInstance) {
callback({
code: grpc.status.UNAVAILABLE,
details: "Chaincode connection is not established."
});
return;
}
const { record_id, operation, data_json } = call.request;
try {
console.log(`Operation requested: ${operation}`);
switch (operation) {
case 'DLTRECORDOPERATION_ADD':
await contractInstance.submitTransaction('StoreRecord', JSON.stringify(record_id), data_json);
break;
case 'DLTRECORDOPERATION_UPDATE':
await contractInstance.submitTransaction('UpdateRecord', JSON.stringify(record_id), data_json);
break;
case 'DLTRECORDOPERATION_DELETE':
await contractInstance.submitTransaction('DeleteRecord', JSON.stringify(record_id));
break;
default:
throw new Error('Invalid operation');
}
// Send success response
callback(null, { record_id, status: 'DLTRECORDSTATUS_SUCCEEDED' });
} catch (error) {
// Send failure response with error message
console.log("ERRROR", error)
callback(null, { record_id, status: 'DLTRECORDSTATUS_FAILED', error_message: error.message });
}
}
// gRPC method to fetch data from the DLT
async function getFromDlt(call, callback) {
if (!contractInstance) {
callback({
code: grpc.status.UNAVAILABLE,
details: "Chaincode connection is not established."
});
return;
}
try {
console.log("RECEIVED CALL REQUEST:", call.request);
//const { record_id, operation, data_json } = call.request;
const resultBytes = await contractInstance.evaluateTransaction('RetrieveRecord', JSON.stringify(call.request));
// Decode and parse the result
const resultJson = utf8Decoder.decode(resultBytes);
const result = JSON.parse(resultJson);
// Send the response with the formatted JSON data
callback(null, { record_id: call.request, operation: result.operation, data_json: result.data_json });
} catch (error) {
if (error.message.includes("data not found for key")) {
// Return an empty response when no record is found
console.log("REQUEST ERROR:", error);
const emptyRecordId = {
domain_uuid: { uuid: "" },
type: 'DLTRECORDTYPE_UNDEFINED',
record_uuid: { uuid: "" }
};
callback(null, { record_id: emptyRecordId, data_json: "" });
} else {
// Send failure response with error message
callback({
code: grpc.status.UNKNOWN,
details: error.message
});
}
}
}
// Implement subscription to DLT events
const eventNameToEventTypeEnum = {
'StoreRecord': 'EVENTTYPE_CREATE',
'UpdateRecord': 'EVENTTYPE_UPDATE',
'DeleteRecord': 'EVENTTYPE_REMOVE'
};
function subscribeToDlt(call) {
if (!events) {
call.emit('error', {
code: grpc.status.UNAVAILABLE,
details: "Event listener is not established."
});
return;
}
// Add the client to the set of active clients
clients.add(call);
console.log(`Client connected. Total clients: ${clients.size}`);
// Clean up when the client disconnects
call.on('cancelled', () => {
clients.delete(call);
console.log(`Client disconnected (cancelled). Total clients: ${clients.size}`);
});
call.on('error', (err) => {
clients.delete(call);
console.log(`Client disconnected (error: ${err.message}). Total clients: ${clients.size}`);
});
call.on('end', () => {
clients.delete(call);
console.log(`Client disconnected (end). Total clients: ${clients.size}`);
});
(async () => {
try {
for await (const event of events) {
const eventPayload = event.payload;
//console.log("Raw event payload:", eventPayload);
const resultJson = utf8Decoder.decode(eventPayload);
const eventJson = JSON.parse(resultJson);
console.log("Writing event to stream:", eventJson.record_id);
const eventType = eventNameToEventTypeEnum[event.eventName] || 'EVENTTYPE_UNDEFINED';
for (const client of clients) {
const writeSuccessful = client.write({
event: {
timestamp: { timestamp: Math.floor(Date.now() / 1000) },
event_type: eventType // Set appropriate event type
},
record_id: {
domain_uuid: { uuid: eventJson.record_id.domain_uuid.uuid },
type: eventJson.record_id.type || 'DLTRECORDTYPE_UNDEFINED',
record_uuid: { uuid: eventJson.record_id.record_uuid.uuid }
}
});
// Check if the internal buffer is full
if (!writeSuccessful) {
// Wait for the 'drain' event before continuing
await new Promise((resolve) => client.once('drain', resolve));
}
}
}
//call.end();
} catch (error) {
for (const client of clients) {
client.emit('error', {
code: grpc.status.UNKNOWN,
details: `Error processing event: ${error.message}`
});
}
}
})();
}
// Placeholder
function getDltStatus(call, callback) {
// Implement status fetching logic here
// Not implemented for simplicity
}
// Placeholder
function getDltPeers(call, callback) {
// Implement peers fetching logic here
// Not implemented for simplicity
}
// Add the service to the server
server.addService(dltProto.DltGatewayService.service, {
RecordToDlt: recordToDlt,
GetFromDlt: getFromDlt,
SubscribeToDlt: subscribeToDlt,
GetDltStatus: getDltStatus,
GetDltPeers: getDltPeers,
});
// Start the server
const PORT = process.env.GRPC_PORT || '50051';
server.bindAsync(`0.0.0.0:${PORT}`, grpc.ServerCredentials.createInsecure(), async (error) => {
if (error) {
console.error('Failed to bind server:', error);
return;
}
console.log(`gRPC server running at http://0.0.0.0:${PORT}`);
await initChaincodeConnection(); //Connects to the chaincode and
server;
});
// Handle shutdown gracefully
process.on('SIGINT', async () => {
console.log('Shutting down...');
await closeConnection();
server.forceShutdown();
});
\ No newline at end of file
// Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import * as grpc from '@grpc/grpc-js';
import { connect, Contract, Identity, Signer, signers, Network, CloseableAsyncIterable, ChaincodeEvent, GatewayError } from '@hyperledger/fabric-gateway';
import * as crypto from 'crypto';
import { promises as fs } from 'fs';
import * as path from 'path';
import { TextDecoder } from 'util';
import * as dotenv from 'dotenv';
dotenv.config({ path: path.resolve(__dirname, '..', '.env') });
const channelName = getEnvVar('CHANNEL_NAME');
const chaincodeName = getEnvVar('CHAINCODE_NAME');
const mspId = getEnvVar('MSP_ID');
// Path to user private key directory.
const keyDirectoryPath = getEnvVar('KEY_DIRECTORY_PATH');
// Path to user certificate directory.
const certDirectoryPath = getEnvVar('CERT_DIRECTORY_PATH');
// Path to peer tls certificate.
const tlsCertPath = getEnvVar('TLS_CERT_PATH');
// Gateway peer endpoint.
const peerEndpoint = getEnvVar('PEER_ENDPOINT');
// Gateway peer SSL host name override.
const peerHostAlias = getEnvVar('PEER_HOST_ALIAS');
const utf8Decoder = new TextDecoder();
const assetId = `asset${Date.now()}`;
export async function connectToNetwork(): Promise<{ contract: Contract, events: CloseableAsyncIterable<ChaincodeEvent>, close: () => Promise<void> }> {
await displayInputParameters();
// The gRPC client connection should be shared by all Gateway connections to this endpoint.
const client = await newGrpcConnection();
const gateway = connect({
client,
identity: await newIdentity(),
signer: await newSigner(),
// Default timeouts for different gRPC calls
evaluateOptions: () => {
return { deadline: Date.now() + 5000 }; // 5 seconds
},
endorseOptions: () => {
return { deadline: Date.now() + 15000 }; // 15 seconds
},
submitOptions: () => {
return { deadline: Date.now() + 5000 }; // 5 seconds
},
commitStatusOptions: () => {
return { deadline: Date.now() + 60000 }; // 1 minute
},
});
let events: CloseableAsyncIterable<ChaincodeEvent> | undefined;
// Get a network instance representing the channel where the smart contract is deployed.
const network = gateway.getNetwork(channelName);
// Get the smart contract from the network.
const contract = network.getContract(chaincodeName);
//Listen for events emitted by transactions
//events = await startEventListening(network);
events = await network.getChaincodeEvents(chaincodeName);
// Initialize the ledger.
await initLedger(contract);
console.log(Date.now())
return {
contract: contract,
events: events,
close: async function () {
if (events) events.close();
gateway.close();
client.close();
}
};
}
async function newGrpcConnection(): Promise<grpc.Client> {
const tlsRootCert = await fs.readFile(tlsCertPath);
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert);
return new grpc.Client(peerEndpoint, tlsCredentials, {
'grpc.ssl_target_name_override': peerHostAlias,
});
}
async function newIdentity(): Promise<Identity> {
//const certPath = await getFirstDirFileName(certDirectoryPath);
//console.log("DEBUG", certDirectoryPath);
const credentials = await fs.readFile(certDirectoryPath);
return { mspId, credentials };
}
async function newSigner(): Promise<Signer> {
//const keyPath = await getFirstDirFileName(keyDirectoryPath);
//console.log("DEBUG2", keyDirectoryPath);
const privateKeyPem = await fs.readFile(keyDirectoryPath);
const privateKey = crypto.createPrivateKey(privateKeyPem);
return signers.newPrivateKeySigner(privateKey);
}
/**
* This type of transaction would typically only be run once by an application the first time it was started after its
* initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function.
*/
async function initLedger(contract: Contract): Promise<void> {
try {
console.log('\n--> Submit Transaction: InitLedger, function activates the chaincode');
await contract.submitTransaction('InitLedger');
console.log('*** Transaction committed successfully');
} catch (error) {
console.error('Failed to submit InitLedger transaction:', error);
throw error;
}
}
/**
* getEnvVar() will return the value of an environment variable.
*/
function getEnvVar(varName: string): string {
const value = process.env[varName];
if (!value) {
throw new Error(`Environment variable ${varName} is not set`);
}
return value;
}
/**
* displayInputParameters() will print the global scope parameters used by the main driver routine.
*/
async function displayInputParameters(): Promise<void> {
console.log(`channelName: ${channelName}`);
console.log(`chaincodeName: ${chaincodeName}`);
console.log(`mspId: ${mspId}`);
console.log(`keyDirectoryPath: ${keyDirectoryPath}`);
console.log(`certDirectoryPath: ${certDirectoryPath}`);
console.log(`tlsCertPath: ${tlsCertPath}`);
console.log(`peerEndpoint: ${peerEndpoint}`);
console.log(`peerHostAlias: ${peerHostAlias}`);
}
/**
* startEventListening() will initiate the event listener for chaincode events.
*/
async function startEventListening(network: Network): Promise<CloseableAsyncIterable<ChaincodeEvent>> {
console.log('\n*** Start chaincode event listening');
const events = await network.getChaincodeEvents(chaincodeName);
void readEvents(events); // Don't await - run asynchronously
return events;
}
/**
* readEvents() format and display the events as a JSON.
*/
async function readEvents(events: CloseableAsyncIterable<ChaincodeEvent>): Promise<void> {
try {
for await (const event of events) {
const payload = parseJson(event.payload);
console.log(`\n<-- Chaincode event received: ${event.eventName} -`, payload);
}
} catch (error: unknown) {
// Ignore the read error when events.close() is called explicitly
if (!(error instanceof GatewayError) || error.code !== grpc.status.CANCELLED.valueOf()) {
throw error;
}
}
}
/**
* parseJson() formats a JSON.
*/
function parseJson(jsonBytes: Uint8Array): unknown {
const json = utf8Decoder.decode(jsonBytes);
return JSON.parse(json);
}
{
"extends":"@tsconfig/node18/tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"outDir": "dist",
"declaration": true,
"sourceMap": true,
"noImplicitAny": true
},
"include": [
"./src/**/*" ],
"exclude": [
"./src/**/*.spec.ts"
]
}
\ No newline at end of file
ca.crt
cert.pem
priv_sk
{
"name": "Network A",
"nodes": [
{
"id": "node1",
"type": "switch",
"status": "active",
"connections": [
"node2",
"node3"
]
},
{
"id": "node2",
"type": "router",
"status": "inactive",
"connections": [
"node1"
]
},
{
"id": "node3",
"type": "server",
"status": "active",
"connections": [
"node1"
]
}
]
}
{
"contexts": [
{"context_id": {"context_uuid": {"uuid": "admin"}}}
],
"topologies": [
{"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}
],
"devices": [
{
"device_id": {"device_uuid": {"uuid": "DC1"}}, "device_type": "emu-datacenter", "device_drivers": [0],
"device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "eth1", "type": "copper"}, {"uuid": "eth2", "type": "copper"}, {"uuid": "int", "type": "copper"}
]}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "DC2"}}, "device_type": "emu-datacenter", "device_drivers": [0],
"device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "eth1", "type": "copper"}, {"uuid": "eth2", "type": "copper"}, {"uuid": "int", "type": "copper"}
]}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "SRL1"}}, "device_type": "packet-router", "device_drivers": [8],
"device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.100.100.101"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "57400"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
"username": "admin", "password": "NokiaSrl1!", "use_tls": true
}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "SRL2"}}, "device_type": "packet-router", "device_drivers": [8],
"device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.100.100.102"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "57400"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
"username": "admin", "password": "NokiaSrl1!", "use_tls": true
}}}
]}
}
],
"links": [
{
"link_id": {"link_uuid": {"uuid": "DC1/eth1==SRL1/ethernet-1/2"}},
"link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "DC1"}}, "endpoint_uuid": {"uuid": "eth1"}},
{"device_id": {"device_uuid": {"uuid": "SRL1"}}, "endpoint_uuid": {"uuid": "ethernet-1/2"}}
]
},
{
"link_id": {"link_uuid": {"uuid": "SRL1/ethernet-1/2==DC1/eth1"}},
"link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "SRL1"}}, "endpoint_uuid": {"uuid": "ethernet-1/2"}},
{"device_id": {"device_uuid": {"uuid": "DC1"}}, "endpoint_uuid": {"uuid": "eth1"}}
]
},
{
"link_id": {"link_uuid": {"uuid": "SRL1/ethernet-1/1==SRL2/ethernet-1/1"}},
"link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "SRL1"}}, "endpoint_uuid": {"uuid": "ethernet-1/1"}},
{"device_id": {"device_uuid": {"uuid": "SRL2"}}, "endpoint_uuid": {"uuid": "ethernet-1/1"}}
]
},
{
"link_id": {"link_uuid": {"uuid": "SRL2/ethernet-1/1==SRL1/ethernet-1/1"}},
"link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "SRL2"}}, "endpoint_uuid": {"uuid": "ethernet-1/1"}},
{"device_id": {"device_uuid": {"uuid": "SRL1"}}, "endpoint_uuid": {"uuid": "ethernet-1/1"}}
]
},
{
"link_id": {"link_uuid": {"uuid": "DC2/eth1==SRL2/ethernet-1/2"}},
"link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "DC2"}}, "endpoint_uuid": {"uuid": "eth1"}},
{"device_id": {"device_uuid": {"uuid": "SRL2"}}, "endpoint_uuid": {"uuid": "ethernet-1/2"}}
]
},
{
"link_id": {"link_uuid": {"uuid": "SRL2/ethernet-1/2==DC2/eth1"}},
"link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "SRL2"}}, "endpoint_uuid": {"uuid": "ethernet-1/2"}},
{"device_id": {"device_uuid": {"uuid": "DC2"}}, "endpoint_uuid": {"uuid": "eth1"}}
]
}
]
}
{
"contexts": [
{"context_id": {"context_uuid": {"uuid": "admin"}}}
],
"topologies": [
{"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}
],
"devices": [
{
"device_id": {"device_uuid": {"uuid": "R1"}}, "device_type": "emu-packet-router", "device_drivers": [0],
"device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/3"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/4"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/5"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/6"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/3"}
]}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "R2"}}, "device_type": "emu-packet-router", "device_drivers": [0],
"device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/3"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/4"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/5"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/6"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/3"}
]}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "R3"}}, "device_type": "emu-packet-router", "device_drivers": [0],
"device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/3"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/4"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/5"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/6"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/3"}
]}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "R4"}}, "device_type": "emu-packet-router", "device_drivers": [0],
"device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/3"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/4"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/5"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/6"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/3"}
]}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "R5"}}, "device_type": "emu-packet-router", "device_drivers": [0],
"device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/3"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/4"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/5"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/6"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/3"}
]}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "R6"}}, "device_type": "emu-packet-router", "device_drivers": [0],
"device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/3"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/4"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/5"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/6"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/3"}
]}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "R7"}}, "device_type": "emu-packet-router", "device_drivers": [0],
"device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "1/3"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/1"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/2"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/3"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/4"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/5"},
{"sample_types": [101, 102, 201, 202], "type": "copper", "uuid": "2/6"}
]}}}
]}
}
],
"links": [
{"link_id": {"link_uuid": {"uuid": "R1==R2"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/1"}},
{"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "2/2"}}
]},
{"link_id": {"link_uuid": {"uuid": "R1==R6"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/2"}},
{"device_id": {"device_uuid": {"uuid": "R6"}}, "endpoint_uuid": {"uuid": "2/1"}}
]},
{"link_id": {"link_uuid": {"uuid": "R1==R7"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/3"}},
{"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/1"}}
]},
{"link_id": {"link_uuid": {"uuid": "R2==R1"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "2/2"}},
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/1"}}
]},
{"link_id": {"link_uuid": {"uuid": "R2==R3"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "2/1"}},
{"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/2"}}
]},
{"link_id": {"link_uuid": {"uuid": "R3==R2"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/2"}},
{"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "2/1"}}
]},
{"link_id": {"link_uuid": {"uuid": "R3==R4"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/1"}},
{"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "2/2"}}
]},
{"link_id": {"link_uuid": {"uuid": "R3==R7"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/3"}},
{"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/3"}}
]},
{"link_id": {"link_uuid": {"uuid": "R4==R3"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "2/2"}},
{"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/1"}}
]},
{"link_id": {"link_uuid": {"uuid": "R4==R5"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "2/1"}},
{"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/2"}}
]},
{"link_id": {"link_uuid": {"uuid": "R5==R4"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/2"}},
{"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "2/1"}}
]},
{"link_id": {"link_uuid": {"uuid": "R5==R6"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/1"}},
{"device_id": {"device_uuid": {"uuid": "R6"}}, "endpoint_uuid": {"uuid": "2/2"}}
]},
{"link_id": {"link_uuid": {"uuid": "R5==R7"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/3"}},
{"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/5"}}
]},
{"link_id": {"link_uuid": {"uuid": "R6==R1"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R6"}}, "endpoint_uuid": {"uuid": "2/1"}},
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/2"}}
]},
{"link_id": {"link_uuid": {"uuid": "R6==R5"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R6"}}, "endpoint_uuid": {"uuid": "2/2"}},
{"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/1"}}
]},
{"link_id": {"link_uuid": {"uuid": "R7==R1"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/1"}},
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/3"}}
]},
{"link_id": {"link_uuid": {"uuid": "R7==R3"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/3"}},
{"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/3"}}
]},
{"link_id": {"link_uuid": {"uuid": "R7==R5"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/5"}},
{"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/3"}}
]}
]
}
{
"contexts": [
{"context_id": {"context_uuid": {"uuid": "admin"}}, "name": "admin"}
],
"topologies": [
{"topology_id": {"topology_uuid": {"uuid": "admin"}, "context_id": {"context_uuid": {"uuid": "admin"}}}, "name": "admin"}
],
"devices": [
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "device_type": "emu-packet-router", "device_operational_status": 1, "device_drivers": [0], "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "client:1", "type": "copper"}, {"uuid": "client:2", "type": "copper"}, {"uuid": "client:3", "type": "copper"},
{"uuid": "be1.be", "type": "copper"}, {"uuid": "pt1.pt", "type": "copper"}, {"uuid": "uk1.uk", "type": "copper"},
{"uuid": "es1.es", "type": "copper"}, {"uuid": "it1.it", "type": "copper"}
]}}}
]}},
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "device_type": "emu-packet-router", "device_operational_status": 1, "device_drivers": [0], "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "client:1", "type": "copper"}, {"uuid": "client:2", "type": "copper"}, {"uuid": "client:3", "type": "copper"},
{"uuid": "de1.de", "type": "copper"}, {"uuid": "gr1.gr", "type": "copper"}, {"uuid": "uk1.uk", "type": "copper"},
{"uuid": "fr1.fr", "type": "copper"}, {"uuid": "it1.it", "type": "copper"}
]}}}
]}},
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "device_type": "emu-packet-router", "device_operational_status": 1, "device_drivers": [0], "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "client:1", "type": "copper"}, {"uuid": "client:2", "type": "copper"}, {"uuid": "client:3", "type": "copper"},
{"uuid": "de1.de", "type": "copper"}, {"uuid": "fr1.fr", "type": "copper"}, {"uuid": "be1.be", "type": "copper"},
{"uuid": "pt1.pt", "type": "copper"}
]}}}
]}},
{"device_id": {"device_uuid": {"uuid": "de1.de"}}, "device_type": "emu-packet-router", "device_operational_status": 1, "device_drivers": [0], "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "client:1", "type": "copper"}, {"uuid": "client:2", "type": "copper"}, {"uuid": "client:3", "type": "copper"},
{"uuid": "uk1.uk", "type": "copper"}, {"uuid": "be1.be", "type": "copper"}, {"uuid": "gr1.gr", "type": "copper"}
]}}}
]}},
{"device_id": {"device_uuid": {"uuid": "pt1.pt"}}, "device_type": "emu-packet-router", "device_operational_status": 1, "device_drivers": [0], "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "client:1", "type": "copper"}, {"uuid": "client:2", "type": "copper"}, {"uuid": "client:3", "type": "copper"},
{"uuid": "uk1.uk", "type": "copper"}, {"uuid": "fr1.fr", "type": "copper"}, {"uuid": "es1.es", "type": "copper"}
]}}}
]}},
{"device_id": {"device_uuid": {"uuid": "es1.es"}}, "device_type": "emu-packet-router", "device_operational_status": 1, "device_drivers": [0], "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "client:1", "type": "copper"}, {"uuid": "client:2", "type": "copper"}, {"uuid": "client:3", "type": "copper"},
{"uuid": "it1.it", "type": "copper"}, {"uuid": "fr1.fr", "type": "copper"}, {"uuid": "pt1.pt", "type": "copper"}
]}}}
]}},
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "device_type": "emu-packet-router", "device_operational_status": 1, "device_drivers": [0], "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "client:1", "type": "copper"}, {"uuid": "client:2", "type": "copper"}, {"uuid": "client:3", "type": "copper"},
{"uuid": "es1.es", "type": "copper"}, {"uuid": "fr1.fr", "type": "copper"}, {"uuid": "be1.be", "type": "copper"},
{"uuid": "gr1.gr", "type": "copper"}
]}}}
]}},
{"device_id": {"device_uuid": {"uuid": "gr1.gr"}}, "device_type": "emu-packet-router", "device_operational_status": 1, "device_drivers": [0], "device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
{"uuid": "client:1", "type": "copper"}, {"uuid": "client:2", "type": "copper"}, {"uuid": "client:3", "type": "copper"},
{"uuid": "it1.it", "type": "copper"}, {"uuid": "de1.de", "type": "copper"}, {"uuid": "be1.be", "type": "copper"}
]}}}
]}}
],
"links": [
{"link_id": {"link_uuid": {"uuid": "fr1.fr_be1.be"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 4.804849}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "be1.be"}},
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "fr1.fr"}}
]},
{"link_id": {"link_uuid": {"uuid": "uk1.uk_fr1.fr"}}, "attributes": {"total_capacity_gbps": 300, "used_capacity_gbps": 55.182499}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "endpoint_uuid": {"uuid": "fr1.fr"}},
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "uk1.uk"}}
]},
{"link_id": {"link_uuid": {"uuid": "uk1.uk_de1.de"}}, "attributes": {"total_capacity_gbps": 600, "used_capacity_gbps": 199.272255}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "endpoint_uuid": {"uuid": "de1.de"}},
{"device_id": {"device_uuid": {"uuid": "de1.de"}}, "endpoint_uuid": {"uuid": "uk1.uk"}}
]},
{"link_id": {"link_uuid": {"uuid": "uk1.uk_be1.be"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 14.334868}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "endpoint_uuid": {"uuid": "be1.be"}},
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "uk1.uk"}}
]},
{"link_id": {"link_uuid": {"uuid": "pt1.pt_uk1.uk"}}, "attributes": {"total_capacity_gbps": 400, "used_capacity_gbps": 51.415678}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "pt1.pt"}}, "endpoint_uuid": {"uuid": "uk1.uk"}},
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "endpoint_uuid": {"uuid": "pt1.pt"}}
]},
{"link_id": {"link_uuid": {"uuid": "pt1.pt_fr1.fr"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 3.733925}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "pt1.pt"}}, "endpoint_uuid": {"uuid": "fr1.fr"}},
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "pt1.pt"}}
]},
{"link_id": {"link_uuid": {"uuid": "pt1.pt_es1.es"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 13.32428}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "pt1.pt"}}, "endpoint_uuid": {"uuid": "es1.es"}},
{"device_id": {"device_uuid": {"uuid": "es1.es"}}, "endpoint_uuid": {"uuid": "pt1.pt"}}
]},
{"link_id": {"link_uuid": {"uuid": "it1.it_gr1.gr"}}, "attributes": {"total_capacity_gbps": 800, "used_capacity_gbps": 1.593313}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "endpoint_uuid": {"uuid": "gr1.gr"}},
{"device_id": {"device_uuid": {"uuid": "gr1.gr"}}, "endpoint_uuid": {"uuid": "it1.it"}}
]},
{"link_id": {"link_uuid": {"uuid": "it1.it_fr1.fr"}}, "attributes": {"total_capacity_gbps": 200, "used_capacity_gbps": 98.574706}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "endpoint_uuid": {"uuid": "fr1.fr"}},
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "it1.it"}}
]},
{"link_id": {"link_uuid": {"uuid": "it1.it_es1.es"}}, "attributes": {"total_capacity_gbps": 300, "used_capacity_gbps": 18.97108}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "endpoint_uuid": {"uuid": "es1.es"}},
{"device_id": {"device_uuid": {"uuid": "es1.es"}}, "endpoint_uuid": {"uuid": "it1.it"}}
]},
{"link_id": {"link_uuid": {"uuid": "it1.it_be1.be"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 10.327772}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "endpoint_uuid": {"uuid": "be1.be"}},
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "it1.it"}}
]},
{"link_id": {"link_uuid": {"uuid": "gr1.gr_it1.it"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 7.983659}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "gr1.gr"}}, "endpoint_uuid": {"uuid": "it1.it"}},
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "endpoint_uuid": {"uuid": "gr1.gr"}}
]},
{"link_id": {"link_uuid": {"uuid": "gr1.gr_de1.de"}}, "attributes": {"total_capacity_gbps": 5000, "used_capacity_gbps": 4930.897339}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "gr1.gr"}}, "endpoint_uuid": {"uuid": "de1.de"}},
{"device_id": {"device_uuid": {"uuid": "de1.de"}}, "endpoint_uuid": {"uuid": "gr1.gr"}}
]},
{"link_id": {"link_uuid": {"uuid": "gr1.gr_be1.be"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 0.895539}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "gr1.gr"}}, "endpoint_uuid": {"uuid": "be1.be"}},
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "gr1.gr"}}
]},
{"link_id": {"link_uuid": {"uuid": "fr1.fr_uk1.uk"}}, "attributes": {"total_capacity_gbps": 200, "used_capacity_gbps": 28.144199}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "uk1.uk"}},
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "endpoint_uuid": {"uuid": "fr1.fr"}}
]},
{"link_id": {"link_uuid": {"uuid": "fr1.fr_pt1.pt"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 1.916587}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "pt1.pt"}},
{"device_id": {"device_uuid": {"uuid": "pt1.pt"}}, "endpoint_uuid": {"uuid": "fr1.fr"}}
]},
{"link_id": {"link_uuid": {"uuid": "fr1.fr_it1.it"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 3.330747}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "it1.it"}},
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "endpoint_uuid": {"uuid": "fr1.fr"}}
]},
{"link_id": {"link_uuid": {"uuid": "fr1.fr_es1.es"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 96.682749}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "es1.es"}},
{"device_id": {"device_uuid": {"uuid": "es1.es"}}, "endpoint_uuid": {"uuid": "fr1.fr"}}
]},
{"link_id": {"link_uuid": {"uuid": "es1.es_pt1.pt"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 5.643483}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "es1.es"}}, "endpoint_uuid": {"uuid": "pt1.pt"}},
{"device_id": {"device_uuid": {"uuid": "pt1.pt"}}, "endpoint_uuid": {"uuid": "es1.es"}}
]},
{"link_id": {"link_uuid": {"uuid": "es1.es_it1.it"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 15.353667}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "es1.es"}}, "endpoint_uuid": {"uuid": "it1.it"}},
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "endpoint_uuid": {"uuid": "es1.es"}}
]},
{"link_id": {"link_uuid": {"uuid": "es1.es_fr1.fr"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 20.517778}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "es1.es"}}, "endpoint_uuid": {"uuid": "fr1.fr"}},
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "es1.es"}}
]},
{"link_id": {"link_uuid": {"uuid": "de1.de_uk1.uk"}}, "attributes": {"total_capacity_gbps": 600, "used_capacity_gbps": 239.446965}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "de1.de"}}, "endpoint_uuid": {"uuid": "uk1.uk"}},
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "endpoint_uuid": {"uuid": "de1.de"}}
]},
{"link_id": {"link_uuid": {"uuid": "de1.de_gr1.gr"}}, "attributes": {"total_capacity_gbps": 2100, "used_capacity_gbps": 110.602237}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "de1.de"}}, "endpoint_uuid": {"uuid": "gr1.gr"}},
{"device_id": {"device_uuid": {"uuid": "gr1.gr"}}, "endpoint_uuid": {"uuid": "de1.de"}}
]},
{"link_id": {"link_uuid": {"uuid": "de1.de_be1.be"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 57.709307}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "de1.de"}}, "endpoint_uuid": {"uuid": "be1.be"}},
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "de1.de"}}
]},
{"link_id": {"link_uuid": {"uuid": "uk1.uk_pt1.pt"}}, "attributes": {"total_capacity_gbps": 800, "used_capacity_gbps": 652.70225}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "endpoint_uuid": {"uuid": "pt1.pt"}},
{"device_id": {"device_uuid": {"uuid": "pt1.pt"}}, "endpoint_uuid": {"uuid": "uk1.uk"}}
]},
{"link_id": {"link_uuid": {"uuid": "be1.be_uk1.uk"}}, "attributes": {"total_capacity_gbps": 200, "used_capacity_gbps": 8.252107}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "uk1.uk"}},
{"device_id": {"device_uuid": {"uuid": "uk1.uk"}}, "endpoint_uuid": {"uuid": "be1.be"}}
]},
{"link_id": {"link_uuid": {"uuid": "be1.be_it1.it"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 0.357069}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "it1.it"}},
{"device_id": {"device_uuid": {"uuid": "it1.it"}}, "endpoint_uuid": {"uuid": "be1.be"}}
]},
{"link_id": {"link_uuid": {"uuid": "be1.be_de1.de"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 20.400142}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "de1.de"}},
{"device_id": {"device_uuid": {"uuid": "de1.de"}}, "endpoint_uuid": {"uuid": "be1.be"}}
]},
{"link_id": {"link_uuid": {"uuid": "be1.be_fr1.fr"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 31.346514}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "fr1.fr"}},
{"device_id": {"device_uuid": {"uuid": "fr1.fr"}}, "endpoint_uuid": {"uuid": "be1.be"}}
]},
{"link_id": {"link_uuid": {"uuid": "be1.be_gr1.gr"}}, "attributes": {"total_capacity_gbps": 100, "used_capacity_gbps": 0.026822}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "be1.be"}}, "endpoint_uuid": {"uuid": "gr1.gr"}},
{"device_id": {"device_uuid": {"uuid": "gr1.gr"}}, "endpoint_uuid": {"uuid": "be1.be"}}
]}
]
}
{
"contexts": [
{"context_id": {"context_uuid": {"uuid": "admin"}}}
],
"topologies": [
{"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}
],
"devices": [
{
"device_id": {"device_uuid": {"uuid": "T1"}}, "device_type": "optical-transponder", "device_drivers": [11],
"device_operational_status": 1,
"device_endpoints": [
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}}
],
"device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.101"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
"username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
"look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
"device_params": {"name": "default"}, "manager_params": {"timeout": 120},
"endpoints": [{"uuid": "1", "type": "optical", "sample_types": [101, 102, 201, 202]}]
}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "T2"}}, "device_type": "optical-transponder", "device_drivers": [11],
"device_operational_status": 1,
"device_endpoints": [
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}}
],
"device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.102"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
"username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
"look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
"device_params": {"name": "default"}, "manager_params": {"timeout": 120},
"endpoints": [{"uuid": "6", "type": "optical", "sample_types": [101, 102, 201, 202]}]
}}}
]}
},
{
"device_id": {"device_uuid": {"uuid": "R1"}}, "device_type": "optical-roadm", "device_drivers": [11],
"device_operational_status": 1,
"device_endpoints": [
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}},
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "3"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}},
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "12"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}},
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "13"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}}
],
"device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.201"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
"username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
"look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
"device_params": {"name": "default"}, "manager_params": {"timeout": 120},
"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "2"},
{"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "3"},
{"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "12"},
{"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "13"}
]}
}}]
}
},
{
"device_id": {"device_uuid": {"uuid": "R2"}}, "device_type": "optical-roadm", "device_drivers": [11],
"device_operational_status": 1,
"device_endpoints": [
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "4"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}},
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "5"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}},
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "14"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}},
{"endpoint_id": {
"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "15"},
"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
}}
],
"device_config": {"config_rules": [
{"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.202"}},
{"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
{"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
"username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
"look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
"device_params": {"name": "default"}, "manager_params": {"timeout": 120},
"endpoints": [
{"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "4"},
{"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "5"},
{"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "14"},
{"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "15"}
]
}}}
]}
}
],
"links": [
{"link_id": {"link_uuid": {"uuid": "T1->R1"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}},
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "12"}}
]},
{"link_id": {"link_uuid": {"uuid": "R1->T1"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2"}},
{"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}}
]},
{"link_id": {"link_uuid": {"uuid": "R1->R2"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "3"}},
{"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "14"}}
]},
{"link_id": {"link_uuid": {"uuid": "R2->R1"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "4"}},
{"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "13"}}
]},
{"link_id": {"link_uuid": {"uuid": "T2->R2"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}},
{"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "15"}}
]},
{"link_id": {"link_uuid": {"uuid": "R2->T2"}}, "link_endpoint_ids": [
{"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "5"}},
{"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}}
]}
]
}
{
"name": "Updated Network",
"nodes": [
{
"id": "node1",
"type": "switch",
"status": "active",
"connections": ["node2"]
},
{
"id": "node2",
"type": "router",
"status": "inactive",
"connections": ["node1"]
}
]
}
// Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const { connectToNetwork } = require('../dltApp/dist/fabricConnect');
const fsp = require('fs').promises;
const fs = require('fs');
const util = require('util');
const utf8Decoder = new TextDecoder();
const topoDirectory = '../samples/';
const topologies = ['topo1.json', 'topo2.json', 'topo3.json', 'topo4.json'];
//const topologies = ['topo4.json'];
const iterations = 1000;
async function main() {
try {
const { contract, close } = await connectToNetwork();
for (const topoFile of topologies) {
const logFilePath = `./operation_times_${topoFile.split('.')[0]}.txt`; // Creates a separate logfile for each topology
const appendFile = util.promisify(fs.appendFile.bind(fs, logFilePath));
console.log(`Starting tests for ${topoFile}`);
for (let i = 0; i < iterations; i++) {
console.log(`Iteration ${i + 1} for ${topoFile}`);
await runBlockchainOperations(contract, topoFile, appendFile);
}
}
await close(); // Clean up the connection
} catch (error) {
console.error('An error occurred:', error);
}
}
async function runBlockchainOperations(contract, topoFile, appendFile) {
const assetId = `asset${Date.now()}`;
const jsonData = await readJsonData(`${topoDirectory}${topoFile}`);
// Define operations
const operations = [
{ type: 'STORE', jsonData },
{ type: 'UPDATE', jsonData },
{ type: 'FETCH', jsonData: null },
{ type: 'DELETE', jsonData: null },
{ type: 'FETCH_ALL', jsonData: null }
];
for (let op of operations) {
await executeOperation(contract, op.type, assetId, op.jsonData, appendFile);
}
}
async function readJsonData(filePath) {
try {
return await fsp.readFile(filePath, 'utf8');
} catch (error) {
console.error(`Failed to read file: ${filePath}`, error);
return '{}';
}
}
async function executeOperation(contract, operationType, assetId, jsonData, appendFile) {
const startTime = process.hrtime.bigint();
try {
let result;
switch (operationType) {
case 'STORE':
result = await contract.submitTransaction('StoreTopoData', assetId, jsonData);
break;
case 'UPDATE':
result = await contract.submitTransaction('UpdateTopoData', assetId, jsonData);
break;
case 'FETCH':
result = await contract.evaluateTransaction('RetrieveTopoData', assetId);
break;
case 'DELETE':
result = await contract.submitTransaction('DeleteTopo', assetId);
break;
case 'FETCH_ALL':
result = await contract.evaluateTransaction('GetAllInfo');
break;
}
result = utf8Decoder.decode(result);
const operationTime = recordOperationTime(startTime);
await logOperationTime(operationTime, operationType, appendFile);
console.log(`${operationType} Result:`, result);
} catch (error) {
console.error(`Error during ${operationType}:`, error);
}
}
function recordOperationTime(startTime) {
const endTime = process.hrtime.bigint();
const operationTime = Number(endTime - startTime) / 1e6;
return operationTime;
}
async function logOperationTime(operationTime, operationType, appendFile) {
const timestamp = Date.now();
const logEntry = `${timestamp} - ${operationType} - Execution time: ${operationTime.toFixed(3)} ms\n`;
try {
await appendFile(logEntry);
} catch (error) {
console, error('Error writing to log file:', error);
}
}
main();
// Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const { connectToNetwork } = require('../dltApp/dist/fabricConnect');
const fs = require('fs');
const util = require('util');
const appendFile = util.promisify(fs.appendFile);
const logFilePath = './transaction_times_TPS_TOPO3.txt';
const utf8Decoder = new TextDecoder();
const topoDirectory = '../samples/';
async function main() {
const { contract, close } = await connectToNetwork();
try {
const rates = [10, 50, 250, 500]; // Transactions per second
for (let i = 0; i < 1000; i++) {
for (let rate of rates) {
console.log(`Testing at ${rate} TPS`);
await performLoadTest(contract, 1000, rate);
}
}
} finally {
await close(); // Ensure to close the network connection
}
}
async function performLoadTest(contract, totalTransactions, rate) {
const interval = 1000 / rate; // Calculate interval in milliseconds
let promises = [];
const startTime = Date.now();
for (let i = 0; i < totalTransactions; i++) {
// Queue a transaction promise
promises.push(sendTransaction(contract, `asset${Date.now() + i}`));
// Process in batches according to the rate
if ((i + 1) % rate === 0 || i === totalTransactions - 1) {
await Promise.all(promises); // Send a batch of transactions
promises = []; // Reset for the next batch
if (i < totalTransactions - 1) {
await new Promise(resolve => setTimeout(resolve, interval)); // Throttle the transaction sending
}
}
}
const endTime = Date.now();
const totalTime = endTime - startTime;
const actualRate = totalTransactions / (totalTime / 1000);
console.log(`Total time for ${totalTransactions} transactions at target ${rate} TPS: ${totalTime} ms`);
console.log(`Actual rate achieved: ${actualRate.toFixed(2)} TPS`);
await appendFile(logFilePath, `Target Rate: ${rate} TPS, Total Time: ${totalTime} ms, Actual Rate: ${actualRate.toFixed(2)} TPS\n`);
}
async function sendTransaction(contract, assetId) {
try {
const jsonData = await readJsonData(`${topoDirectory}topo3.json`);
const result = await contract.submitTransaction('StoreTopoData', assetId, jsonData);
return utf8Decoder.decode(result);
} catch (error) {
console.error('Transaction failed:', error);
return null;
}
}
async function readJsonData(filePath) {
try {
return await fs.promises.readFile(filePath, 'utf8');
} catch (error) {
console.error(`Failed to read file: ${filePath}`, error);
return '{}';
}
}
main().catch(console.error);
// Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const { connectToNetwork } = require('../dltApp/dist/fabricConnect');
const fs = require('fs');
const util = require('util');
const appendFile = util.promisify(fs.appendFile);
const logFilePath = './transaction_times_TPS2.txt';
const utf8Decoder = new TextDecoder();
const topoDirectory = '../samples/';
async function main() {
const { contract, close } = await connectToNetwork();
try {
console.log('Testing with 8 consecutive transactions');
await performLoadTest(contract);
} finally {
await close(); // Ensure to close the network connection
}
}
async function performLoadTest(contract) {
const totalTransactions = 500;
const promises = [];
const startTime = Date.now();
for (let i = 0; i < totalTransactions; i++) {
// Queue a transaction promise
promises.push(sendTransaction(contract, `asset${startTime}_${i}`));
}
await Promise.all(promises); // Send all transactions
const endTime = Date.now();
const totalTime = endTime - startTime;
const actualRate = totalTransactions / (totalTime / 1000);
console.log(`Total time for ${totalTransactions} transactions: ${totalTime} ms`);
console.log(`Actual rate achieved: ${actualRate.toFixed(2)} TPS`);
await appendFile(logFilePath, `Total Transactions: ${totalTransactions}, Total Time: ${totalTime} ms, Actual Rate: ${actualRate.toFixed(2)} TPS\n`);
}
async function sendTransaction(contract, assetId) {
try {
const jsonData = await readJsonData(`${topoDirectory}topo4.json`);
//const jsonData = JSON.stringify({ data: `Data for ${assetId}`});
const result = await contract.submitTransaction('StoreTopoData', assetId, jsonData);
return utf8Decoder.decode(result);
} catch (error) {
console.error('Transaction failed:', error);
return null;
}
}
async function readJsonData(filePath) {
try {
return await fs.promises.readFile(filePath, 'utf8');
} catch (error) {
console.error(`Failed to read file: ${filePath}`, error);
return '{}';
}
}
main().catch(console.error);
// Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const path = require('path');
const PROTO_PATH = path.resolve(__dirname, '../../../../proto/dlt_gateway.proto');
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const dltProto = grpc.loadPackageDefinition(packageDefinition).dlt;
const client = new dltProto.DltGatewayService(
'127.0.0.1:32001', // Replace with TFS server IP_ADDRESS
grpc.credentials.createInsecure()
);
function subscribeToDlt() {
const request = {
// Define any necessary subscription filters here if applicable
};
const call = client.SubscribeToDlt(request);
call.on('data', (event) => {
console.log('Received event:', event);
});
call.on('error', (error) => {
console.error('Error:', error.message);
});
call.on('end', () => {
console.log('Stream ended.');
});
// Optionally, you can cancel the subscription after a certain time or condition
setTimeout(() => {
console.log('Cancelling subscription...');
call.cancel();
}, 600000); // Cancel after 1 minute for demonstration purposes
}
function runTests() {
console.log("Testing subscription to DLT events");
subscribeToDlt();
}
runTests();
// Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const path = require('path');
const fs = require('fs').promises;
const { v4: uuidv4 } = require('uuid'); // Import the UUID library
const PROTO_PATH = path.resolve(__dirname, '../../../../proto/dlt_gateway.proto');
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const dltProto = grpc.loadPackageDefinition(packageDefinition).dlt;
const client = new dltProto.DltGatewayService(
'127.0.0.1:32001', // Replace with TFS server IP_ADDRESS
grpc.credentials.createInsecure()
);
const assetId = `asset-${Date.now()}`;
const domainUuid = `domain-${uuidv4()}`; // Generate a pretty domain UUID
async function getTopoData(filename) {
try {
const data = await fs.readFile(`../samples/${filename}`, 'utf8');
return data;
} catch (error) {
console.error('Failed to read file:', filename, error);
return '{}'; // Empty JSON if error
}
}
async function processTopoData(operation, assetId, jsonFilename) {
let jsonData = '{}';
if (jsonFilename) {
jsonData = await getTopoData(jsonFilename);
}
const request = {
record_id: {
domain_uuid: { uuid: domainUuid }, // Replace "domain-uuid" with actual domain UUID if needed
type: 'DLTRECORDTYPE_TOPOLOGY', // Use the appropriate type if needed
record_uuid: { uuid: assetId }
},
operation,
data_json: jsonData
};
return new Promise((resolve, reject) => {
client.RecordToDlt(request, (error, response) => {
if (error) {
console.error('Error:', error.message);
reject(error);
} else {
console.log('Response:', response);
resolve(response);
}
});
});
}
async function getDLTData(assetId) {
const request = {
domain_uuid: { uuid: domainUuid }, // Replace "domain-uuid" with actual domain UUID if needed
type: 'DLTRECORDTYPE_TOPOLOGY', // Use the appropriate type if needed
record_uuid: { uuid: assetId }
};
return new Promise((resolve, reject) => {
client.GetFromDlt(request, (error, response) => {
if (error) {
console.error('Error:', error.message);
reject(error);
} else {
console.log('Response:', response);
resolve(response);
}
});
});
}
async function runTests() {
console.log("Testing Store Operation");
await processTopoData('DLTRECORDOPERATION_ADD', assetId, 'topo2.json');
console.log("Testing Update Operation");
await processTopoData('DLTRECORDOPERATION_UPDATE', assetId, 'topo3.json');
console.log("Testing Fetch Operation");
await getDLTData(assetId);
console.log("Testing Delete Operation");
await processTopoData('DLTRECORDOPERATION_DELETE', assetId);
console.log("Testing Fetch All Operation");
// This part assumes you have a GetAllInfo method implemented in your chaincode and corresponding gRPC service.
// client.GetAllInfo({}, (error, response) => {
// if (error) {
// console.error('Error:', error.message);
// } else {
// console.log('All Data:', response);
// }
// });
}
runTests().catch(console.error);
......@@ -15,6 +15,7 @@
from common.Settings import get_setting
SETTING_NAME_TOPOLOGY_ABSTRACTOR = 'TOPOLOGY_ABSTRACTOR'
SETTING_NAME_DLT_INTEGRATION = 'DLT_INTEGRATION'
TRUE_VALUES = {'Y', 'YES', 'TRUE', 'T', 'E', 'ENABLE', 'ENABLED'}
def is_topology_abstractor_enabled() -> bool:
......@@ -22,3 +23,9 @@ def is_topology_abstractor_enabled() -> bool:
if is_enabled is None: return False
str_is_enabled = str(is_enabled).upper()
return str_is_enabled in TRUE_VALUES
def is_dlt_enabled() -> bool:
is_enabled = get_setting(SETTING_NAME_DLT_INTEGRATION, default=None)
if is_enabled is None: return False
str_is_enabled = str(is_enabled).upper()
return str_is_enabled in TRUE_VALUES
......@@ -34,7 +34,7 @@ from common.tools.object_factory.Device import json_device_id
from common.tools.object_factory.EndPoint import json_endpoint_id
from common.tools.object_factory.Topology import json_topology_id
from context.client.ContextClient import ContextClient
from dlt.connector.client.DltConnectorClient import DltConnectorClient
from dlt.connector.client.DltConnectorClientAsync import DltConnectorClientAsync
from pathcomp.frontend.client.PathCompClient import PathCompClient
from service.client.ServiceClient import ServiceClient
from slice.client.SliceClient import SliceClient
......@@ -88,7 +88,7 @@ class InterdomainServiceServicerImpl(InterdomainServiceServicer):
])
if len(env_vars) == 2:
# DLT available
dlt_connector_client = DltConnectorClient()
dlt_connector_client = DltConnectorClientAsync()
dlt_connector_client.connect()
else:
dlt_connector_client = None
......
......@@ -18,8 +18,9 @@ from common.Constants import ServiceNameEnum
from common.Settings import (
ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_log_level, get_metrics_port,
wait_for_environment_variables)
from interdomain.Config import is_topology_abstractor_enabled
from interdomain.Config import is_dlt_enabled, is_topology_abstractor_enabled
from .topology_abstractor.TopologyAbstractor import TopologyAbstractor
from .topology_abstractor.DltRecorder import DLTRecorder
from .InterdomainService import InterdomainService
from .RemoteDomainClients import RemoteDomainClients
......@@ -69,12 +70,21 @@ def main():
topology_abstractor = TopologyAbstractor()
topology_abstractor.start()
# Subscribe to Context Events
dlt_enabled = is_dlt_enabled()
if dlt_enabled:
LOGGER.info('Starting DLT functionality...')
dlt_recorder = DLTRecorder()
dlt_recorder.start()
# Wait for Ctrl+C or termination signal
while not terminate.wait(timeout=1.0): pass
LOGGER.info('Terminating...')
if topology_abstractor_enabled:
topology_abstractor.stop()
if dlt_enabled:
dlt_recorder.stop()
grpc_service.stop()
remote_domain_clients.stop()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment