327 lines
9.6 KiB
V
327 lines
9.6 KiB
V
module tfgrid3deployer
|
|
|
|
import freeflowuniverse.herolib.threefold.grid.models as grid_models
|
|
import freeflowuniverse.herolib.threefold.gridproxy
|
|
import freeflowuniverse.herolib.threefold.grid
|
|
import freeflowuniverse.herolib.ui.console
|
|
import json
|
|
import rand
|
|
|
|
// NetworkInfo struct to represent network details
|
|
pub struct NetworkSpecs {
|
|
pub mut:
|
|
name string = 'net' + rand.string(5)
|
|
ip_range string = '10.10.0.0/16'
|
|
mycelium string = rand.hex(64)
|
|
}
|
|
|
|
struct NetworkHandler {
|
|
mut:
|
|
network_name string
|
|
nodes []u32
|
|
ip_range string
|
|
wg_ports map[u32]u16
|
|
wg_keys map[u32][]string
|
|
wg_subnet map[u32]string
|
|
endpoints map[u32]string
|
|
public_node u32
|
|
hidden_nodes []u32
|
|
none_accessible_ip_ranges []string
|
|
mycelium string
|
|
|
|
deployer &grid.Deployer @[skip; str: skip]
|
|
}
|
|
|
|
// TODO: maybe rename to fill_network or something similar
|
|
fn (mut self NetworkHandler) create_network(vmachines []VMachine) ! {
|
|
// Set nodes
|
|
self.nodes = []
|
|
|
|
for vmachine in vmachines {
|
|
if !self.nodes.contains(vmachine.node_id) {
|
|
self.nodes << vmachine.node_id
|
|
}
|
|
}
|
|
|
|
console.print_header('Network nodes: ${self.nodes}.')
|
|
self.setup_wireguard_data()!
|
|
self.setup_access_node()!
|
|
}
|
|
|
|
fn (mut self NetworkHandler) generate_workload(node_id u32, peers []grid_models.Peer, mycleium_hex_key string) !grid_models.Workload {
|
|
mut network_workload := grid_models.Znet{
|
|
ip_range: self.ip_range
|
|
subnet: self.wg_subnet[node_id]
|
|
wireguard_private_key: self.wg_keys[node_id][0]
|
|
wireguard_listen_port: self.wg_ports[node_id]
|
|
peers: peers
|
|
mycelium: grid_models.Mycelium{
|
|
hex_key: mycleium_hex_key
|
|
peers: []
|
|
}
|
|
}
|
|
|
|
return network_workload.to_workload(
|
|
name: self.network_name
|
|
description: 'VGridClient network workload'
|
|
)
|
|
}
|
|
|
|
fn (mut self NetworkHandler) prepare_hidden_node_peers(node_id u32) ![]grid_models.Peer {
|
|
mut peers := []grid_models.Peer{}
|
|
if self.public_node != 0 {
|
|
peers << grid_models.Peer{
|
|
subnet: self.wg_subnet[self.public_node]
|
|
wireguard_public_key: self.wg_keys[self.public_node][1]
|
|
allowed_ips: [self.ip_range, '100.64.0.0/16']
|
|
endpoint: '${self.endpoints[self.public_node]}:${self.wg_ports[self.public_node]}'
|
|
}
|
|
}
|
|
return peers
|
|
}
|
|
|
|
fn (mut self NetworkHandler) setup_access_node() ! {
|
|
// Case 1: Deployment on 28 which is hidden node
|
|
// - Setup access node
|
|
// Case 2: Deployment on 11 which is public node
|
|
// - Already have the access node
|
|
// Case 3: if the saved state has already public node.
|
|
// - Check the new deployment if its node is hidden take the saved one
|
|
// - if the access node is already set, that means we have set its values e.g. the wireguard port, keys
|
|
|
|
if self.hidden_nodes.len < 1 || self.nodes.len == 1 {
|
|
self.public_node = 0
|
|
return
|
|
}
|
|
|
|
if self.public_node != 0 {
|
|
if !self.nodes.contains(self.public_node) {
|
|
self.nodes << self.public_node
|
|
}
|
|
return
|
|
}
|
|
|
|
/*
|
|
- In this case a public node should be assigned.
|
|
- We need to store it somewhere to inform the user that the deployment has one more contract on another node,
|
|
also delete that contract when delete the full deployment.
|
|
- Assign the public node with the new node id.
|
|
*/
|
|
console.print_header('No public nodes found based on your specs.')
|
|
console.print_header('Requesting the Proxy to assign a public node.')
|
|
|
|
nodes := filter_nodes(
|
|
ipv4: true
|
|
status: 'up'
|
|
healthy: true
|
|
available_for: u64(self.deployer.twin_id)
|
|
features: [
|
|
'zmachine',
|
|
]
|
|
)!
|
|
if nodes.len == 0 {
|
|
return error('Requested the Grid Proxy and no nodes found.')
|
|
}
|
|
|
|
access_node := pick_node(mut self.deployer, nodes) or {
|
|
return error('Failed to pick valid node: ${err}')
|
|
}
|
|
self.public_node = u32(access_node.node_id)
|
|
|
|
console.print_header('Public node ${self.public_node}')
|
|
|
|
self.nodes << self.public_node
|
|
|
|
wg_port := self.deployer.assign_wg_port(self.public_node)!
|
|
keys := self.deployer.client.generate_wg_priv_key()! // The first index will be the private.
|
|
mut parts := self.ip_range.split('/')[0].split('.')
|
|
parts[2] = '${self.nodes.len + 2}'
|
|
subnet := parts.join('.') + '/24'
|
|
|
|
self.wg_ports[self.public_node] = wg_port
|
|
self.wg_keys[self.public_node] = keys
|
|
self.wg_subnet[self.public_node] = subnet
|
|
self.endpoints[self.public_node] = access_node.public_config.ipv4.split('/')[0]
|
|
}
|
|
|
|
fn (mut self NetworkHandler) setup_wireguard_data() ! {
|
|
// TODO: We need to set the extra node
|
|
console.print_header('Setting up network workload.')
|
|
self.hidden_nodes, self.none_accessible_ip_ranges = [], []
|
|
|
|
for node_id in self.nodes {
|
|
// TODO: Check if there values don't re-generate
|
|
mut public_config := self.deployer.get_node_pub_config(node_id) or {
|
|
if err.msg().contains('no public configuration') {
|
|
grid_models.PublicConfig{}
|
|
} else {
|
|
return error('Failed to get node public config: ${err}')
|
|
}
|
|
}
|
|
|
|
if _ := self.wg_ports[node_id] {
|
|
// The node already exists
|
|
if public_config.ipv4.len != 0 {
|
|
self.endpoints[node_id] = public_config.ipv4.split('/')[0]
|
|
if self.public_node == 0 {
|
|
self.public_node = node_id
|
|
}
|
|
} else if public_config.ipv6.len != 0 {
|
|
self.endpoints[node_id] = public_config.ipv6.split('/')[0]
|
|
} else {
|
|
self.hidden_nodes << node_id
|
|
self.none_accessible_ip_ranges << self.wg_subnet[node_id]
|
|
self.none_accessible_ip_ranges << wireguard_routing_ip(self.wg_subnet[node_id])
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
self.wg_ports[node_id] = self.deployer.assign_wg_port(node_id)!
|
|
|
|
self.wg_keys[node_id] = self.deployer.client.generate_wg_priv_key()!
|
|
|
|
self.wg_subnet[node_id] = self.calculate_subnet()!
|
|
|
|
if public_config.ipv4.len != 0 {
|
|
self.endpoints[node_id] = public_config.ipv4.split('/')[0]
|
|
self.public_node = node_id
|
|
} else if public_config.ipv6.len != 0 {
|
|
self.endpoints[node_id] = public_config.ipv6.split('/')[0]
|
|
} else {
|
|
self.hidden_nodes << node_id
|
|
self.none_accessible_ip_ranges << self.wg_subnet[node_id]
|
|
self.none_accessible_ip_ranges << wireguard_routing_ip(self.wg_subnet[node_id])
|
|
}
|
|
}
|
|
}
|
|
|
|
fn (mut self NetworkHandler) prepare_public_node_peers(node_id u32) ![]grid_models.Peer {
|
|
mut peers := []grid_models.Peer{}
|
|
for peer_id in self.nodes {
|
|
if peer_id in self.hidden_nodes || peer_id == node_id {
|
|
continue
|
|
}
|
|
|
|
subnet := self.wg_subnet[peer_id]
|
|
mut allowed_ips := [subnet, wireguard_routing_ip(subnet)]
|
|
|
|
if peer_id == self.public_node {
|
|
allowed_ips << self.none_accessible_ip_ranges
|
|
}
|
|
|
|
peers << grid_models.Peer{
|
|
subnet: subnet
|
|
wireguard_public_key: self.wg_keys[peer_id][1]
|
|
allowed_ips: allowed_ips
|
|
endpoint: '${self.endpoints[peer_id]}:${self.wg_ports[peer_id]}'
|
|
}
|
|
}
|
|
|
|
if node_id == self.public_node {
|
|
for hidden_node_id in self.hidden_nodes {
|
|
subnet := self.wg_subnet[hidden_node_id]
|
|
routing_ip := wireguard_routing_ip(subnet)
|
|
|
|
peers << grid_models.Peer{
|
|
subnet: subnet
|
|
wireguard_public_key: self.wg_keys[hidden_node_id][1]
|
|
allowed_ips: [subnet, routing_ip]
|
|
endpoint: ''
|
|
}
|
|
}
|
|
}
|
|
|
|
return peers
|
|
}
|
|
|
|
fn (mut self NetworkHandler) calculate_subnet() !string {
|
|
mut parts := self.ip_range.split('/')[0].split('.')
|
|
for i := 2; i <= 255; i += 1 {
|
|
parts[2] = '${i}'
|
|
candidate := parts.join('.') + '/24'
|
|
if !self.wg_subnet.values().contains(candidate) {
|
|
return candidate
|
|
}
|
|
}
|
|
|
|
return error('failed to calcuate subnet')
|
|
}
|
|
|
|
fn (mut self NetworkHandler) load_network_state(dls map[u32]grid_models.Deployment) ! {
|
|
// load network from deployments
|
|
|
|
mut network_name := ''
|
|
mut subnet_node := map[string]u32{}
|
|
mut subnet_to_endpoint := map[string]string{}
|
|
for node_id, dl in dls {
|
|
mut znet := grid_models.Znet{}
|
|
for wl in dl.workloads {
|
|
network_name = wl.name
|
|
if wl.type_ == grid_models.workload_types.network {
|
|
znet = json.decode(grid_models.Znet, wl.data)!
|
|
break
|
|
}
|
|
}
|
|
|
|
if znet.subnet == '' {
|
|
// deployment didn't have a network workload. skip..
|
|
continue
|
|
}
|
|
|
|
self.network_name = network_name
|
|
self.nodes << node_id
|
|
self.ip_range = znet.ip_range
|
|
self.wg_ports[node_id] = znet.wireguard_listen_port
|
|
self.wg_keys[node_id] = [znet.wireguard_private_key,
|
|
self.deployer.client.generate_wg_public_key(znet.wireguard_private_key)!]
|
|
self.wg_subnet[node_id] = znet.subnet
|
|
self.mycelium = if myclelium := znet.mycelium { myclelium.hex_key } else { '' }
|
|
subnet_node[znet.subnet] = node_id
|
|
for peer in znet.peers {
|
|
subnet_to_endpoint[peer.subnet] = peer.endpoint
|
|
|
|
if peer.endpoint == '' {
|
|
// current node is the access node
|
|
self.public_node = node_id
|
|
}
|
|
}
|
|
}
|
|
|
|
for subnet, endpoint in subnet_to_endpoint {
|
|
node_id := subnet_node[subnet]
|
|
if endpoint == '' {
|
|
self.hidden_nodes << node_id
|
|
continue
|
|
}
|
|
self.endpoints[node_id] = endpoint.all_before_last(':').trim('[]')
|
|
}
|
|
|
|
for node_id in self.hidden_nodes {
|
|
self.none_accessible_ip_ranges << self.wg_subnet[node_id]
|
|
self.none_accessible_ip_ranges << wireguard_routing_ip(self.wg_subnet[node_id])
|
|
}
|
|
}
|
|
|
|
fn (mut self NetworkHandler) generate_workloads() !map[u32]grid_models.Workload {
|
|
mut workloads := map[u32]grid_models.Workload{}
|
|
for node_id in self.nodes {
|
|
if node_id in self.hidden_nodes {
|
|
mut peers := self.prepare_hidden_node_peers(node_id)!
|
|
workloads[node_id] = self.generate_workload(node_id, peers, self.mycelium)!
|
|
continue
|
|
}
|
|
|
|
mut peers := self.prepare_public_node_peers(node_id)!
|
|
workloads[node_id] = self.generate_workload(node_id, peers, self.mycelium)!
|
|
}
|
|
|
|
return workloads
|
|
}
|
|
|
|
fn (mut n NetworkHandler) remove_node(node_id u32) ! {
|
|
}
|
|
|
|
fn (mut n NetworkHandler) add_node() ! {
|
|
}
|