added docker templating and introducted possbility to change the baseimage name

This commit is contained in:
2023-08-23 22:45:46 +01:00
parent dfa8713aea
commit 6b287f2cf1
9 changed files with 1061 additions and 990 deletions

2
.gitignore vendored
View File

@@ -21,6 +21,8 @@ generate/Test
#ignore windows exe files #ignore windows exe files
*.exe *.exe
dist/ dist/
# Ignore any sort of logs
logs/
# ignore docker image files # ignore docker image files
server/docker/containers/ server/docker/containers/

View File

@@ -19,7 +19,7 @@ var (
// From the selected server IP address // From the selected server IP address
// TODO: Test cases for this function // TODO: Test cases for this function
// Calls URL ex: http://0.0.0.0:8088/startcontainer?ports=0&GPU=false&ContainerName=docker-ubuntu-sshd // Calls URL ex: http://0.0.0.0:8088/startcontainer?ports=0&GPU=false&ContainerName=docker-ubuntu-sshd
func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string) (*docker.DockerVM, error) { func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string, baseImage string) (*docker.DockerVM, error) {
// Passes URL with number of TCP ports to allocated and to give GPU access to the docker container // Passes URL with number of TCP ports to allocated and to give GPU access to the docker container
var URL string var URL string
//version := p2p.Ip4or6(IP) //version := p2p.Ip4or6(IP)
@@ -33,7 +33,7 @@ func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string) (*d
//if version == "version 6" { //if version == "version 6" {
// URL = "http://[" + IP + "]:" + serverPort + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName // URL = "http://[" + IP + "]:" + serverPort + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName
//} else { //} else {
URL = "http://" + IP + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName URL = "http://" + IP + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName + "&BaseImage=" + baseImage
//} //}
resp, err := http.Get(URL) resp, err := http.Get(URL)

View File

@@ -1,277 +1,277 @@
package cmd package cmd
import ( import (
"fmt" "fmt"
"github.com/Akilan1999/p2p-rendering-computation/client" "github.com/Akilan1999/p2p-rendering-computation/client"
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable" "github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
"github.com/Akilan1999/p2p-rendering-computation/config/generate" "github.com/Akilan1999/p2p-rendering-computation/config/generate"
"github.com/Akilan1999/p2p-rendering-computation/p2p" "github.com/Akilan1999/p2p-rendering-computation/p2p"
"github.com/Akilan1999/p2p-rendering-computation/plugin" "github.com/Akilan1999/p2p-rendering-computation/plugin"
"github.com/Akilan1999/p2p-rendering-computation/server" "github.com/Akilan1999/p2p-rendering-computation/server"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
var CliAction = func(ctx *cli.Context) error { var CliAction = func(ctx *cli.Context) error {
if Server { if Server {
_, err := server.Server() _, err := server.Server()
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
//server.Rpc() //server.Rpc()
for { for {
} }
} }
//Listing servers and also updates IP tables (Default 3 hops) //Listing servers and also updates IP tables (Default 3 hops)
if UpdateServerList { if UpdateServerList {
err := clientIPTable.UpdateIpTableListClient() err := clientIPTable.UpdateIpTableListClient()
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
// Reads from ip table and passes it // Reads from ip table and passes it
// on to struct print function // on to struct print function
//Servers, err := p2p.ReadIpTable() //Servers, err := p2p.ReadIpTable()
//if err != nil { //if err != nil {
// return err // return err
//} //}
//client.PrettyPrint(Servers) //client.PrettyPrint(Servers)
p2p.PrintIpTable() p2p.PrintIpTable()
} }
// Displays the IP table // Displays the IP table
if ServerList { if ServerList {
// Reads from ip table and passes it // Reads from ip table and passes it
// on to struct print function // on to struct print function
//Servers, err := p2p.ReadIpTable() //Servers, err := p2p.ReadIpTable()
//if err != nil { //if err != nil {
// return err // return err
//} //}
p2p.PrintIpTable() p2p.PrintIpTable()
} }
// Add provided IP to the IP table // Add provided IP to the IP table
if AddServer != "" { if AddServer != "" {
res, err := p2p.ReadIpTable() res, err := p2p.ReadIpTable()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
//Create variable of type IpAddress and set IP address //Create variable of type IpAddress and set IP address
// to it // to it
var IpAddr p2p.IpAddress var IpAddr p2p.IpAddress
//Checking if the address is a ipv4 //Checking if the address is a ipv4
// or ipv6 address // or ipv6 address
ip4Orip6 := p2p.Ip4or6(AddServer) ip4Orip6 := p2p.Ip4or6(AddServer)
if ip4Orip6 == "version 6" { if ip4Orip6 == "version 6" {
IpAddr.Ipv6 = AddServer IpAddr.Ipv6 = AddServer
} else { } else {
IpAddr.Ipv4 = AddServer IpAddr.Ipv4 = AddServer
} }
// If a server port is provided then set it // If a server port is provided then set it
if Ports != "" { if Ports != "" {
IpAddr.ServerPort = Ports IpAddr.ServerPort = Ports
} else { } else {
IpAddr.ServerPort = "8088" IpAddr.ServerPort = "8088"
} }
// Append IP address to variable result which // Append IP address to variable result which
// is a list // is a list
res.IpAddress = append(res.IpAddress, IpAddr) res.IpAddress = append(res.IpAddress, IpAddr)
// Adds the new server IP to the iptable // Adds the new server IP to the iptable
res.WriteIpTable() res.WriteIpTable()
} }
// Displays all images available on the server side // Displays all images available on the server side
if ViewImages != "" { if ViewImages != "" {
imageRes, err := client.ViewContainers(ViewImages) imageRes, err := client.ViewContainers(ViewImages)
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
client.PrettyPrint(imageRes) client.PrettyPrint(imageRes)
} }
// Function called to stop and remove server from Docker // Function called to stop and remove server from Docker
if RemoveVM != "" { if RemoveVM != "" {
if ID == "" { if ID == "" {
fmt.Println("provide container ID via --ID or --id") fmt.Println("provide container ID via --ID or --id")
} else { } else {
err := client.RemoveContianer(RemoveVM, ID) err := client.RemoveContianer(RemoveVM, ID)
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
} }
} }
//Call function to create Docker container //Call function to create Docker container
if CreateVM != "" { if CreateVM != "" {
var PortsInt int var PortsInt int
if Ports != "" { if Ports != "" {
// Convert Get Request value to int // Convert Get Request value to int
fmt.Sscanf(Ports, "%d", &PortsInt) fmt.Sscanf(Ports, "%d", &PortsInt)
} }
// Calls function to do Api call to start the container on the server side // Calls function to do Api call to start the container on the server side
imageRes, err := client.StartContainer(CreateVM, PortsInt, GPU, ContainerName) imageRes, err := client.StartContainer(CreateVM, PortsInt, GPU, ContainerName, BaseImage)
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
client.PrettyPrint(imageRes) client.PrettyPrint(imageRes)
} }
//Call if specs flag is called //Call if specs flag is called
if Specs != "" { if Specs != "" {
specs, err := client.GetSpecs(Specs) specs, err := client.GetSpecs(Specs)
if err != nil { if err != nil {
return err return err
} }
// Pretty print // Pretty print
client.PrettyPrint(specs) client.PrettyPrint(specs)
} }
//Sets default paths to the config file //Sets default paths to the config file
if SetDefaultConfig { if SetDefaultConfig {
_, err := generate.SetDefaults("P2PRC", false, nil, false) _, err := generate.SetDefaults("P2PRC", false, nil, false)
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
} }
//If the network interface flag is called //If the network interface flag is called
// Then all the network interfaces are displayed // Then all the network interfaces are displayed
if NetworkInterface { if NetworkInterface {
err := p2p.ViewNetworkInterface() err := p2p.ViewNetworkInterface()
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
} }
// If the view plugin flag is called then display all // If the view plugin flag is called then display all
// plugins available // plugins available
if ViewPlugin { if ViewPlugin {
plugins, err := plugin.DetectPlugins() plugins, err := plugin.DetectPlugins()
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
client.PrettyPrint(plugins) client.PrettyPrint(plugins)
} }
// If the flag Tracked Container is called or the flag // If the flag Tracked Container is called or the flag
// --tc // --tc
if TrackedContainers { if TrackedContainers {
err, trackedContainers := client.ViewTrackedContainers() err, trackedContainers := client.ViewTrackedContainers()
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
} }
client.PrettyPrint(trackedContainers) client.PrettyPrint(trackedContainers)
} }
//Executing plugin when the plugin flag is called //Executing plugin when the plugin flag is called
// --plugin // --plugin
if ExecutePlugin != "" { if ExecutePlugin != "" {
// To execute plugin requires the container ID or group ID provided when being executed // To execute plugin requires the container ID or group ID provided when being executed
if ID != "" { if ID != "" {
err := plugin.CheckRunPlugin(ExecutePlugin, ID) err := plugin.CheckRunPlugin(ExecutePlugin, ID)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
fmt.Println("Success") fmt.Println("Success")
} }
} else { } else {
fmt.Println("provide container ID via --ID or --id") fmt.Println("provide container ID via --ID or --id")
} }
} }
// Executing function to create new group // Executing function to create new group
// Creates new group and outputs JSON file // Creates new group and outputs JSON file
if CreateGroup { if CreateGroup {
group, err := client.CreateGroup() group, err := client.CreateGroup()
if err != nil { if err != nil {
return err return err
} }
client.PrettyPrint(group) client.PrettyPrint(group)
} }
// Actions to be performed when the // Actions to be performed when the
// group flag is called // group flag is called
// --group <Group ID> // --group <Group ID>
if Group != "" { if Group != "" {
// Remove container from group based on group ID provided // Remove container from group based on group ID provided
// --rmcgroup --id <contianer id> // --rmcgroup --id <contianer id>
if RemoveContainerGroup && ID != "" { if RemoveContainerGroup && ID != "" {
group, err := client.RemoveContainerGroup(ID, Group) group, err := client.RemoveContainerGroup(ID, Group)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
client.PrettyPrint(group) client.PrettyPrint(group)
} }
} else if ID != "" { // Add container to group based on group ID provided } else if ID != "" { // Add container to group based on group ID provided
// --id <Container ID> // --id <Container ID>
group, err := client.AddContainerToGroup(ID, Group) group, err := client.AddContainerToGroup(ID, Group)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
client.PrettyPrint(group) client.PrettyPrint(group)
} }
} else { // View all information about current group } else { // View all information about current group
group, err := client.GetGroup(Group) group, err := client.GetGroup(Group)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
client.PrettyPrint(group) client.PrettyPrint(group)
} }
} }
} }
// Execute function to remove entire group // Execute function to remove entire group
// when remove group flag is called // when remove group flag is called
// --rmgroup // --rmgroup
if RemoveGroup != "" { if RemoveGroup != "" {
err := client.RemoveGroup(RemoveGroup) err := client.RemoveGroup(RemoveGroup)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
fmt.Println("Group Removed") fmt.Println("Group Removed")
} }
} }
// Execute Function to view all groups // Execute Function to view all groups
if Groups { if Groups {
groups, err := client.ReadGroup() groups, err := client.ReadGroup()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
client.PrettyPrint(groups) client.PrettyPrint(groups)
} }
} }
//-------------------------------- //--------------------------------
if PullPlugin != "" { if PullPlugin != "" {
err := plugin.DownloadPlugin(PullPlugin) err := plugin.DownloadPlugin(PullPlugin)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
fmt.Println("Success") fmt.Println("Success")
} }
} }
if RemovePlugin != "" { if RemovePlugin != "" {
err := plugin.DeletePlugin(RemovePlugin) err := plugin.DeletePlugin(RemovePlugin)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
fmt.Println("Success") fmt.Println("Success")
} }
} }
return nil return nil
} }

View File

@@ -10,6 +10,7 @@ var (
ViewImages string ViewImages string
CreateVM string CreateVM string
ContainerName string ContainerName string
BaseImage string
Ports string Ports string
Server bool Server bool
RemoveVM string RemoveVM string
@@ -89,6 +90,13 @@ var AppConfigFlags = []cli.Flag{
EnvVars: []string{"CONTAINER_NAME"}, EnvVars: []string{"CONTAINER_NAME"},
Destination: &ContainerName, Destination: &ContainerName,
}, },
&cli.StringFlag{
Name: "BaseImage",
Aliases: []string{"bi"},
Usage: "Specifying the docker base image to template the dockerfile",
EnvVars: []string{"CONTAINER_NAME"},
Destination: &BaseImage,
},
&cli.StringFlag{ &cli.StringFlag{
Name: "RemoveVM", Name: "RemoveVM",
Aliases: []string{"rm"}, Aliases: []string{"rm"},

View File

@@ -1,52 +1,53 @@
package config package config
import ( import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"os" "os"
) )
var ( var (
//defaultPath string //defaultPath string
defaults = map[string]interface{}{} defaults = map[string]interface{}{}
configName = "config" configName = "config"
configType = "json" configType = "json"
configFile = "config.json" configFile = "config.json"
configPaths []string configPaths []string
defaultEnvName = "P2PRC" defaultEnvName = "P2PRC"
) )
type Config struct { type Config struct {
MachineName string MachineName string
IPTable string IPTable string
DockerContainers string DockerContainers string
DefaultDockerFile string DefaultDockerFile string
SpeedTestFile string DockerRunLogs string
IPV6Address string SpeedTestFile string
PluginPath string IPV6Address string
TrackContainersPath string PluginPath string
ServerPort string TrackContainersPath string
GroupTrackContainersPath string ServerPort string
FRPServerPort string GroupTrackContainersPath string
BehindNAT string FRPServerPort string
CustomConfig interface{} BehindNAT string
//NetworkInterface string CustomConfig interface{}
//NetworkInterfaceIPV6Index int //NetworkInterface string
//NetworkInterfaceIPV6Index int
} }
// GetPathP2PRC Getting P2PRC Directory from environment variable // GetPathP2PRC Getting P2PRC Directory from environment variable
func GetPathP2PRC(Envname string) (string, error) { func GetPathP2PRC(Envname string) (string, error) {
if Envname != "" { if Envname != "" {
err := SetEnvName(Envname) err := SetEnvName(Envname)
if err != nil { if err != nil {
return "", err return "", err
} }
} }
curDir := os.Getenv(defaultEnvName) curDir := os.Getenv(defaultEnvName)
if curDir == "" { if curDir == "" {
return curDir, nil return curDir, nil
} }
return curDir + "/", nil return curDir + "/", nil
} }
// SetEnvName Sets the environment name // SetEnvName Sets the environment name
@@ -54,103 +55,103 @@ func GetPathP2PRC(Envname string) (string, error) {
// your environment variable // your environment variable
// This is useful when extending the use case of P2PRC // This is useful when extending the use case of P2PRC
func SetEnvName(EnvName string) error { func SetEnvName(EnvName string) error {
defaultEnvName = EnvName defaultEnvName = EnvName
// Handling error to be implemented only if needed // Handling error to be implemented only if needed
return nil return nil
} }
func GetEnvName() string { func GetEnvName() string {
return defaultEnvName return defaultEnvName
} }
// ConfigInit Pass environment name as an optional parameter // ConfigInit Pass environment name as an optional parameter
func ConfigInit(defaultsParameter map[string]interface{}, CustomConfig interface{}, envNameOptional ...string) (*Config, error) { func ConfigInit(defaultsParameter map[string]interface{}, CustomConfig interface{}, envNameOptional ...string) (*Config, error) {
if len(envNameOptional) > 0 { if len(envNameOptional) > 0 {
defaultEnvName = envNameOptional[0] defaultEnvName = envNameOptional[0]
} }
// //
////Setting current directory to default path ////Setting current directory to default path
//defaultPath, err := GetPathP2PRC(defaultEnvName) //defaultPath, err := GetPathP2PRC(defaultEnvName)
//if err != nil { //if err != nil {
// return nil, err // return nil, err
//} //}
////Paths to search for config file ////Paths to search for config file
//configPaths = append(configPaths, defaultPath) //configPaths = append(configPaths, defaultPath)
// //
////Add all possible configurations paths ////Add all possible configurations paths
//for _, v := range configPaths { //for _, v := range configPaths {
// viper.AddConfigPath(v) // viper.AddConfigPath(v)
//} //}
// //
////Read config file ////Read config file
//if err := viper.ReadInConfig(); err != nil { //if err := viper.ReadInConfig(); err != nil {
// // If the error thrown is config file not found // // If the error thrown is config file not found
// //Sets default configuration to viper // //Sets default configuration to viper
// for k, v := range defaults { // for k, v := range defaults {
// viper.SetDefault(k, v) // viper.SetDefault(k, v)
// } // }
// viper.SetConfigName(configName) // viper.SetConfigName(configName)
// viper.SetConfigFile(configFile) // viper.SetConfigFile(configFile)
// viper.SetConfigType(configType) // viper.SetConfigType(configType)
// //
// if err = viper.WriteConfig(); err != nil { // if err = viper.WriteConfig(); err != nil {
// return nil, err // return nil, err
// } // }
//} //}
// //
//// Adds configuration to the struct //// Adds configuration to the struct
//var config Config //var config Config
//if err := viper.Unmarshal(&config); err != nil { //if err := viper.Unmarshal(&config); err != nil {
// return nil, err // return nil, err
//} //}
// //
//return &config, nil //return &config, nil
defaultPath, err := GetPathP2PRC(defaultEnvName) defaultPath, err := GetPathP2PRC(defaultEnvName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Open our jsonFile // Open our jsonFile
jsonFile, err := os.Open(defaultPath + configFile) jsonFile, err := os.Open(defaultPath + configFile)
// if we os.Open returns an error then handle it // if we os.Open returns an error then handle it
if err != nil { if err != nil {
return nil, err return nil, err
} }
// defer the closing of our jsonFile so that we can parse it later on // defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close() defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile) byteValue, _ := ioutil.ReadAll(jsonFile)
var config Config var config Config
json.Unmarshal(byteValue, &config) json.Unmarshal(byteValue, &config)
if CustomConfig != nil { if CustomConfig != nil {
// Convert Custom Config to byte // Convert Custom Config to byte
customConfigByte, err := json.Marshal(config.CustomConfig) customConfigByte, err := json.Marshal(config.CustomConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Again map the byte to the CustomConfig interface // Again map the byte to the CustomConfig interface
json.Unmarshal(customConfigByte, &CustomConfig) json.Unmarshal(customConfigByte, &CustomConfig)
} }
return &config, nil return &config, nil
} }
func (c *Config) WriteConfig() error { func (c *Config) WriteConfig() error {
//Getting Current Directory from environment variable //Getting Current Directory from environment variable
//curDir := os.Getenv("REMOTEGAMING") //curDir := os.Getenv("REMOTEGAMING")
defaultPath, err := GetPathP2PRC(defaultEnvName) defaultPath, err := GetPathP2PRC(defaultEnvName)
if err != nil { if err != nil {
return err return err
} }
file, _ := json.MarshalIndent(c, "", " ") file, _ := json.MarshalIndent(c, "", " ")
_ = ioutil.WriteFile(defaultPath+"config.json", file, 0644) _ = ioutil.WriteFile(defaultPath+"config.json", file, 0644)
return nil return nil
} }

View File

@@ -1,20 +1,20 @@
package generate package generate
import ( import (
"github.com/Akilan1999/p2p-rendering-computation/config" "github.com/Akilan1999/p2p-rendering-computation/config"
"os" "os"
) )
var ( var (
defaults = map[string]interface{}{} defaults = map[string]interface{}{}
configPaths []string configPaths []string
defaultEnvName = "P2PRC" defaultEnvName = "P2PRC"
) )
// GetPathP2PRC Getting P2PRC Directory from environment variable // GetPathP2PRC Getting P2PRC Directory from environment variable
func GetPathP2PRC() (string, error) { func GetPathP2PRC() (string, error) {
curDir := os.Getenv(defaultEnvName) curDir := os.Getenv(defaultEnvName)
return curDir + "/", nil return curDir + "/", nil
} }
// SetEnvName Sets the environment name // SetEnvName Sets the environment name
@@ -22,110 +22,111 @@ func GetPathP2PRC() (string, error) {
// your environment variable // your environment variable
// This is useful when extending the use case of P2PRC // This is useful when extending the use case of P2PRC
func SetEnvName(EnvName string) error { func SetEnvName(EnvName string) error {
if EnvName != "" { if EnvName != "" {
defaultEnvName = EnvName defaultEnvName = EnvName
} }
// Handling error to be implemented only if needed // Handling error to be implemented only if needed
return nil return nil
} }
// GetCurrentPath Getting P2PRC Directory from environment variable // GetCurrentPath Getting P2PRC Directory from environment variable
func GetCurrentPath() (string, error) { func GetCurrentPath() (string, error) {
curDir := os.Getenv("PWD") curDir := os.Getenv("PWD")
return curDir + "/", nil return curDir + "/", nil
} }
// SetDefaults This function to be called only during a // SetDefaults This function to be called only during a
// make install // make install
func SetDefaults(envName string, forceDefault bool, CustomConfig interface{}, NoBoilerPlate bool, ConfigUpdate ...*config.Config) (*config.Config, error) { func SetDefaults(envName string, forceDefault bool, CustomConfig interface{}, NoBoilerPlate bool, ConfigUpdate ...*config.Config) (*config.Config, error) {
//Setting current directory to default path //Setting current directory to default path
defaultPath, err := GetCurrentPath() defaultPath, err := GetCurrentPath()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Set Env name // Set Env name
err = config.SetEnvName(envName) err = config.SetEnvName(envName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
////Creates ip_table.json in the json directory ////Creates ip_table.json in the json directory
//err = Copy("p2p/ip_table.json", "p2p/iptable/ip_table.json") //err = Copy("p2p/ip_table.json", "p2p/iptable/ip_table.json")
//if err != nil { //if err != nil {
// return err // return err
//} //}
// //
////Creates a copy of trackcontainers.json in the appropriate directory ////Creates a copy of trackcontainers.json in the appropriate directory
//err = Copy("client/trackcontainers.json", "client/trackcontainers/trackcontainers.json") //err = Copy("client/trackcontainers.json", "client/trackcontainers/trackcontainers.json")
//if err != nil { //if err != nil {
// return err // return err
//} //}
// //
////Creates a copy of trackcontainers.json in the appropriate directory ////Creates a copy of trackcontainers.json in the appropriate directory
//err = Copy("client/grouptrackcontainers.json", "client/trackcontainers/grouptrackcontainers.json") //err = Copy("client/grouptrackcontainers.json", "client/trackcontainers/grouptrackcontainers.json")
//if err != nil { //if err != nil {
// return err // return err
//} //}
var Defaults config.Config var Defaults config.Config
if len(ConfigUpdate) == 0 { if len(ConfigUpdate) == 0 {
//Setting default paths for the config file //Setting default paths for the config file
Defaults.IPTable = defaultPath + "p2p/iptable/ip_table.json" Defaults.IPTable = defaultPath + "p2p/iptable/ip_table.json"
Defaults.DefaultDockerFile = defaultPath + "server/docker/containers/docker-ubuntu-sshd/" Defaults.DefaultDockerFile = defaultPath + "server/docker/containers/docker-ubuntu-sshd/"
Defaults.DockerContainers = defaultPath + "server/docker/containers/" Defaults.DockerContainers = defaultPath + "server/docker/containers/"
Defaults.SpeedTestFile = defaultPath + "p2p/50.bin" Defaults.SpeedTestFile = defaultPath + "p2p/50.bin"
Defaults.IPV6Address = "" Defaults.IPV6Address = ""
Defaults.PluginPath = defaultPath + "plugin/deploy" Defaults.PluginPath = defaultPath + "plugin/deploy"
Defaults.TrackContainersPath = defaultPath + "client/trackcontainers/trackcontainers.json" Defaults.TrackContainersPath = defaultPath + "client/trackcontainers/trackcontainers.json"
Defaults.GroupTrackContainersPath = defaultPath + "client/trackcontainers/grouptrackcontainers.json" Defaults.GroupTrackContainersPath = defaultPath + "client/trackcontainers/grouptrackcontainers.json"
Defaults.ServerPort = "8088" Defaults.ServerPort = "8088"
Defaults.FRPServerPort = "True" Defaults.FRPServerPort = "True"
Defaults.CustomConfig = CustomConfig Defaults.CustomConfig = CustomConfig
Defaults.BehindNAT = "True" Defaults.BehindNAT = "True"
// Random name generator Defaults.DockerRunLogs = "/tmp/"
hostname, err := os.Hostname() // Random name generator
if err != nil { hostname, err := os.Hostname()
return nil, err if err != nil {
} return nil, err
}
Defaults.MachineName = hostname Defaults.MachineName = hostname
} else { } else {
Defaults = *ConfigUpdate[0] Defaults = *ConfigUpdate[0]
} }
//defaults["NetworkInterface"] = "wlp0s20f3" //defaults["NetworkInterface"] = "wlp0s20f3"
//defaults["NetworkInterfaceIPV6Index"] = "2" //defaults["NetworkInterfaceIPV6Index"] = "2"
//Paths to search for config file //Paths to search for config file
configPaths = append(configPaths, defaultPath) configPaths = append(configPaths, defaultPath)
if fileExists(defaultPath+"config.json") && forceDefault { if fileExists(defaultPath+"config.json") && forceDefault {
err := os.Remove(defaultPath + "config.json") err := os.Remove(defaultPath + "config.json")
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
// write defaults to the config file // write defaults to the config file
err = Defaults.WriteConfig() err = Defaults.WriteConfig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
//Calling configuration file //Calling configuration file
Config, err := config.ConfigInit(defaults, nil, envName) Config, err := config.ConfigInit(defaults, nil, envName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !NoBoilerPlate { if !NoBoilerPlate {
err = GenerateFiles() err = GenerateFiles()
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
return Config, nil return Config, nil
} }

View File

@@ -1,202 +1,230 @@
package docker package docker
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context" "encoding/json"
"encoding/json" "errors"
"errors" "fmt"
"fmt" "github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/config" "github.com/docker/docker/client"
"github.com/docker/docker/api/types" "github.com/google/uuid"
"github.com/docker/docker/api/types/container" "github.com/lithammer/shortuuid"
"github.com/docker/docker/client" "github.com/otiai10/copy"
"github.com/docker/docker/pkg/archive" "github.com/phayes/freeport"
"github.com/docker/go-connections/nat" "io"
"github.com/lithammer/shortuuid" "io/ioutil"
"github.com/phayes/freeport" "os"
"io" "os/exec"
"io/ioutil" "text/template"
"os/exec"
"time"
) )
type DockerVM struct { type DockerVM struct {
SSHUsername string `json:"SSHUsername"` SSHUsername string `json:"SSHUsername"`
SSHPassword string `json:"SSHPassword"` SSHPassword string `json:"SSHPassword"`
ID string `json:"ID"` ID string `json:"ID"`
TagName string `json:"TagName"` TagName string `json:"TagName"`
ImagePath string `json:"ImagePath"` ImagePath string `json:"ImagePath"`
Ports Ports `json:"Ports"` Ports Ports `json:"Ports"`
GPU string `json:"GPU"` GPU string `json:"GPU"`
TempPath string
BaseImage string
LogsPath string
} }
type DockerContainers struct { type DockerContainers struct {
DockerContainer []DockerContainer `json:"DockerContainer"` DockerContainer []DockerContainer `json:"DockerContainer"`
} }
type DockerContainer struct { type DockerContainer struct {
ContainerName string `json:"DockerContainerName"` ContainerName string `json:"DockerContainerName"`
ContainerDescription string `json:"ContainerDescription"` ContainerDescription string `json:"ContainerDescription"`
} }
type Ports struct { type Ports struct {
PortSet []Port `json:"Port"` PortSet []Port `json:"Port"`
} }
type Port struct { type Port struct {
PortName string `json:"PortName"` PortName string `json:"PortName"`
InternalPort int `json:"InternalPort"` InternalPort int `json:"InternalPort"`
Type string `json:"Type"` Type string `json:"Type"`
ExternalPort int `json:"ExternalPort"` ExternalPort int `json:"ExternalPort"`
IsUsed bool `json:"IsUsed"` IsUsed bool `json:"IsUsed"`
Description string `json:"Description"` Description string `json:"Description"`
} }
type ErrorLine struct { type ErrorLine struct {
Error string `json:"error"` Error string `json:"error"`
ErrorDetail ErrorDetail `json:"errorDetail"` ErrorDetail ErrorDetail `json:"errorDetail"`
} }
type ErrorDetail struct { type ErrorDetail struct {
Message string `json:"message"` Message string `json:"message"`
} }
var dockerRegistryUserID = "" var dockerRegistryUserID = ""
// BuildRunContainer Function is incharge to invoke building and running contianer and also allocating external // BuildRunContainer Function is incharge to invoke building and running contianer and also allocating external
// ports // ports
func BuildRunContainer(NumPorts int, GPU string, ContainerName string) (*DockerVM, error) { func BuildRunContainer(NumPorts int, GPU string, ContainerName string, baseImage string) (*DockerVM, error) {
//Docker Struct Variable //Docker Struct Variable
var RespDocker *DockerVM = new(DockerVM) var RespDocker *DockerVM = new(DockerVM)
// Sets if GPU is selected or not // Sets if GPU is selected or not
RespDocker.GPU = GPU RespDocker.GPU = GPU
// Sets Free port to Struct // Sets Free port to Struct
//RespDocker.SSHPort = Ports[0] //RespDocker.SSHPort = Ports[0]
//RespDocker.VNCPort = Ports[1] //RespDocker.VNCPort = Ports[1]
// Sets appropriate username and password to the // Sets appropriate username and password to the
// variables in the struct // variables in the struct
RespDocker.SSHUsername = "master" RespDocker.SSHUsername = "master"
RespDocker.SSHPassword = "password" RespDocker.SSHPassword = "password"
//RespDocker.VNCPassword = "vncpassword" //RespDocker.BaseImage = "ubuntu:20.04"
//RespDocker.VNCPassword = "vncpassword"
//Default parameters //Default parameters
RespDocker.TagName = "p2p-ubuntu" RespDocker.TagName = "p2p-ubuntu"
// Get Path from config // Get Path from config
config, err := config.ConfigInit(nil, nil) config, err := config.ConfigInit(nil, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
RespDocker.ImagePath = config.DefaultDockerFile RespDocker.ImagePath = config.DefaultDockerFile
RespDocker.LogsPath = config.DockerRunLogs
// We are checking if the container name is not nil and not equal to the default one used // We are checking if the container name is not nil and not equal to the default one used
// which is docker-ubuntu-sshd // which is docker-ubuntu-sshd
if ContainerName != "" && ContainerName != "docker-ubuntu-sshd" { if ContainerName != "" && ContainerName != "docker-ubuntu-sshd" {
Containers, err := ViewAllContainers() Containers, err := ViewAllContainers()
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, dockerContainer := range Containers.DockerContainer { for _, dockerContainer := range Containers.DockerContainer {
if dockerContainer.ContainerName == ContainerName { if dockerContainer.ContainerName == ContainerName {
RespDocker.ImagePath = config.DockerContainers + ContainerName + "/" RespDocker.ImagePath = config.DockerContainers + ContainerName + "/"
RespDocker.TagName = ContainerName RespDocker.TagName = ContainerName
break break
} }
} }
if RespDocker.ImagePath == config.DefaultDockerFile { if RespDocker.ImagePath == config.DefaultDockerFile {
return nil, errors.New("Container " + ContainerName + " does not exist in the server") return nil, errors.New("Container " + ContainerName + " does not exist in the server")
} }
} }
PortsInformation, err := OpenPortsFile(RespDocker.ImagePath + "/ports.json") // Checking if the base image is provided
if err != nil { if baseImage != "" {
return nil, err RespDocker.BaseImage = baseImage
} } else {
RespDocker.BaseImage = "ubuntu:20.04"
}
// Number of perts we want to open + number of ports required inside the // Template docker with the base image provided
// docker container err = RespDocker.TemplateDockerContainer()
count := NumPorts + len(PortsInformation.PortSet) if err != nil {
// Creates number of ports return nil, err
OpenPorts, err := freeport.GetFreePorts(count) }
if err != nil {
return nil, err
}
// Allocate external ports to ports available in the ports.json file
for i := range PortsInformation.PortSet {
// Setting external ports
PortsInformation.PortSet[i].ExternalPort = OpenPorts[i]
PortsInformation.PortSet[i].IsUsed = true
}
//Length of Ports allocated from thr port file
portFileLength := len(PortsInformation.PortSet)
// Allocate New ports the user wants to generate
for i := 0; i < NumPorts; i++ {
var TempPort Port
TempPort.PortName = "AutoGen Port"
TempPort.Type = "tcp"
TempPort.InternalPort = OpenPorts[portFileLength+i]
TempPort.ExternalPort = OpenPorts[portFileLength+i]
TempPort.Description = "Auto generated TCP port"
TempPort.IsUsed = false
//Append temp port to port information
PortsInformation.PortSet = append(PortsInformation.PortSet, TempPort)
}
// Setting ports to the docker VM struct
RespDocker.Ports = *PortsInformation
// Gets docker information from env variables // Template the DockerFile and point to the temp location
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
}
// Builds docker image PortsInformation, err := OpenPortsFile(RespDocker.ImagePath + "/" + RespDocker.TagName + "/ports.json")
err = RespDocker.imageBuild(cli) if err != nil {
if err != nil { return nil, err
return nil, err }
}
// Runs docker contianer // Number of perts we want to open + number of ports required inside the
err = RespDocker.runContainer(cli) // docker container
count := NumPorts + len(PortsInformation.PortSet)
// Creates number of ports
OpenPorts, err := freeport.GetFreePorts(count)
if err != nil {
return nil, err
}
// Allocate external ports to ports available in the ports.json file
for i := range PortsInformation.PortSet {
// Setting external ports
PortsInformation.PortSet[i].ExternalPort = OpenPorts[i]
PortsInformation.PortSet[i].IsUsed = true
}
//Length of Ports allocated from thr port file
portFileLength := len(PortsInformation.PortSet)
// Allocate New ports the user wants to generate
for i := 0; i < NumPorts; i++ {
var TempPort Port
TempPort.PortName = "AutoGen Port"
TempPort.Type = "tcp"
TempPort.InternalPort = OpenPorts[portFileLength+i]
TempPort.ExternalPort = OpenPorts[portFileLength+i]
TempPort.Description = "Auto generated TCP port"
TempPort.IsUsed = false
//Append temp port to port information
PortsInformation.PortSet = append(PortsInformation.PortSet, TempPort)
}
// Setting ports to the docker VM struct
RespDocker.Ports = *PortsInformation
if err != nil { // Gets docker information from env variables
return nil, err cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
} if err != nil {
return nil, err
}
return RespDocker, nil // Builds docker image
err = RespDocker.imageBuild(cli)
if err != nil {
return nil, err
}
// Runs docker contianer
err = RespDocker.runContainer(cli)
if err != nil {
return nil, err
}
return RespDocker, nil
} }
// Builds docker image (TODO: relative path for Dockerfile deploy) // Builds docker image (TODO: relative path for Dockerfile deploy)
func (d *DockerVM) imageBuild(dockerClient *client.Client) error { func (d *DockerVM) imageBuild(dockerClient *client.Client) error {
ctx, _ := context.WithTimeout(context.Background(), time.Second*2000) //ctx, _ := context.WithTimeout(context.Background(), time.Second*2000)
//defer cancel() //defer cancel()
tar, err := archive.TarWithOptions(d.ImagePath, &archive.TarOptions{}) var cmd bytes.Buffer
if err != nil {
return err
}
opts := types.ImageBuildOptions{ cmd.WriteString("docker build -t " + d.TagName + " " + d.ImagePath + "/" + d.TagName)
Dockerfile: "Dockerfile", //"-v=/opt/data:/data p2p-ubuntu /start > /dev/null"
Tags: []string{d.TagName}, cmdStr := cmd.String()
Remove: true, _, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
} if err != nil {
res, err := dockerClient.ImageBuild(ctx, tar, opts) return err
if err != nil { }
return err
}
defer res.Body.Close() //tar, err := archive.TarWithOptions(d.ImagePath+"/"+d.TagName, &archive.TarOptions{})
//if err != nil {
// return err
//}
//
//opts := types.ImageBuildOptions{
// Dockerfile: "Dockerfile",
// Tags: []string{d.TagName},
// Remove: true,
//}
//res, err := dockerClient.ImageBuild(ctx, tar, opts)
//if err != nil {
// return err
//}
//
//defer res.Body.Close()
//
//err = print(res.Body)
//if err != nil {
// return err
//}
err = print(res.Body) return nil
if err != nil {
return err
}
return nil
} }
// Starts container and assigns port numbers // Starts container and assigns port numbers
@@ -205,200 +233,273 @@ func (d *DockerVM) imageBuild(dockerClient *client.Client) error {
// -p 3443:6901 -p 3453:22 -p 3434:3434 -p 3245:3245 -v=/opt/data:/data // -p 3443:6901 -p 3453:22 -p 3434:3434 -p 3245:3245 -v=/opt/data:/data
// p2p-ubuntu /start > /dev/null // p2p-ubuntu /start > /dev/null
func (d *DockerVM) runContainer(dockerClient *client.Client) error { func (d *DockerVM) runContainer(dockerClient *client.Client) error {
ctx, _ := context.WithTimeout(context.Background(), time.Second*2000) //ctx, _ := context.WithTimeout(context.Background(), time.Second*2000)
// The first mode runs using the Docker Api. As the API supports using // The first mode runs using the Docker Api. As the API supports using
// CPU and uses a shell script for GPU call because till this point of // CPU and uses a shell script for GPU call because till this point of
// implementation docker api does not support the flag "--gpu all" // implementation docker api does not support the flag "--gpu all"
if d.GPU != "true" { //if d.GPU != "true" {
//Exposed ports for docker config file // //Exposed ports for docker config file
var ExposedPort nat.PortSet // var ExposedPort nat.PortSet
//
// ExposedPort = nat.PortSet{
// "22/tcp": struct{}{},
// //"6901/tcp": struct{}{},
// }
//
// // Port forwarding for VNC and SSH ports
// PortForwarding := nat.PortMap{
// //"22/tcp": []nat.PortBinding{
// // {
// // HostIP: "0.0.0.0",
// // HostPort: fmt.Sprint(d.SSHPort),
// // },
// //},
// //"6901/tcp": []nat.PortBinding{
// // {
// // HostIP: "0.0.0.0",
// // HostPort: fmt.Sprint(d.VNCPort),
// // },
// //},
// }
//
// for i := range d.Ports.PortSet {
// // Parameters "tcp or udp", external port
// Port, err := nat.NewPort(d.Ports.PortSet[i].Type, fmt.Sprint(d.Ports.PortSet[i].InternalPort))
// if err != nil {
// return err
// }
//
// // Exposed Ports
// ExposedPort[Port] = struct{}{}
//
// PortForwarding[Port] = []nat.PortBinding{
// {
// HostIP: "0.0.0.0",
// HostPort: fmt.Sprint(d.Ports.PortSet[i].ExternalPort),
// },
// }
// }
//
// config := &container.Config{
// Image: d.TagName,
// Entrypoint: []string{"/start"},
// Volumes: map[string]struct{}{"/opt/data:/data": {}},
// ExposedPorts: ExposedPort,
// }
// hostConfig := &container.HostConfig{
// PortBindings: PortForwarding,
// }
//
// res, err := dockerClient.ContainerCreate(ctx, config, hostConfig,
// nil, nil, "")
//
// // Set response ID
// d.ID = res.ID
//
// if err != nil {
// return err
// }
//
// err = dockerClient.ContainerStart(ctx, res.ID, types.ContainerStartOptions{})
//
// if err != nil {
// return err
// }
//} else {
// Generate Random ID
id := shortuuid.New()
d.ID = id
ExposedPort = nat.PortSet{ var cmd bytes.Buffer
"22/tcp": struct{}{}, cmd.WriteString("docker run -d=true --name=" + id + " --restart=always ")
//"6901/tcp": struct{}{}, if d.GPU == "true" {
} cmd.WriteString("--gpus all ")
}
// Port forwarding for VNC and SSH ports for i := range d.Ports.PortSet {
PortForwarding := nat.PortMap{ cmd.WriteString("-p " + fmt.Sprint(d.Ports.PortSet[i].ExternalPort) + ":" + fmt.Sprint(d.Ports.PortSet[i].InternalPort) + " ")
//"22/tcp": []nat.PortBinding{ }
// { cmd.WriteString("-v=/tmp:/data " + d.TagName + " > /dev/null")
// HostIP: "0.0.0.0", //"-v=/opt/data:/data p2p-ubuntu /start > /dev/null"
// HostPort: fmt.Sprint(d.SSHPort), cmdStr := cmd.String()
// }, _, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
//}, if err != nil {
//"6901/tcp": []nat.PortBinding{ return err
// { }
// HostIP: "0.0.0.0", //}
// HostPort: fmt.Sprint(d.VNCPort), return nil
// },
//},
}
for i := range d.Ports.PortSet {
// Parameters "tcp or udp", external port
Port, err := nat.NewPort(d.Ports.PortSet[i].Type, fmt.Sprint(d.Ports.PortSet[i].InternalPort))
if err != nil {
return err
}
// Exposed Ports
ExposedPort[Port] = struct{}{}
PortForwarding[Port] = []nat.PortBinding{
{
HostIP: "0.0.0.0",
HostPort: fmt.Sprint(d.Ports.PortSet[i].ExternalPort),
},
}
}
config := &container.Config{
Image: d.TagName,
Entrypoint: []string{"/start"},
Volumes: map[string]struct{}{"/opt/data:/data": {}},
ExposedPorts: ExposedPort,
}
hostConfig := &container.HostConfig{
PortBindings: PortForwarding,
}
res, err := dockerClient.ContainerCreate(ctx, config, hostConfig,
nil, nil, "")
// Set response ID
d.ID = res.ID
if err != nil {
return err
}
err = dockerClient.ContainerStart(ctx, res.ID, types.ContainerStartOptions{})
if err != nil {
return err
}
} else {
// Generate Random ID
id := shortuuid.New()
d.ID = id
var cmd bytes.Buffer
cmd.WriteString("docker run -d=true --name=" + id + " --restart=always --gpus all ")
for i := range d.Ports.PortSet {
cmd.WriteString("-p " + fmt.Sprint(d.Ports.PortSet[i].ExternalPort) + ":" + fmt.Sprint(d.Ports.PortSet[i].InternalPort) + " ")
}
cmd.WriteString("-v=/opt/data:/data " + d.TagName + " /start > /dev/null")
//"-v=/opt/data:/data p2p-ubuntu /start > /dev/null"
cmdStr := cmd.String()
_, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
if err != nil {
return err
}
}
return nil
} }
// StopAndRemoveContainer // StopAndRemoveContainer
// Stop and remove a container // Stop and remove a container
// Reference (https://gist.github.com/frikky/e2efcea6c733ea8d8d015b7fe8a91bf6) // Reference (https://gist.github.com/frikky/e2efcea6c733ea8d8d015b7fe8a91bf6)
func StopAndRemoveContainer(containername string) error { func StopAndRemoveContainer(containername string) error {
ctx := context.Background() //ctx := context.Background()
//
//// Gets docker information from env variables
//client, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
//if err != nil {
// return err
//}
//
//if err = client.ContainerStop(ctx, containername, nil); err != nil {
// return err
//}
//
//removeOptions := types.ContainerRemoveOptions{
// RemoveVolumes: true,
// Force: true,
//}
//
//if err = client.ContainerRemove(ctx, containername, removeOptions); err != nil {
// return err
//}
// Gets docker information from env variables // stop docker container
client, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) var stop bytes.Buffer
if err != nil { stop.WriteString("docker stop " + containername)
return err
}
if err = client.ContainerStop(ctx, containername, nil); err != nil { cmdStr := stop.String()
return err _, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
} if err != nil {
return err
}
removeOptions := types.ContainerRemoveOptions{ // remove docker container
RemoveVolumes: true, var remove bytes.Buffer
Force: true, remove.WriteString("docker remove " + containername)
}
if err = client.ContainerRemove(ctx, containername, removeOptions); err != nil { cmdStr = remove.String()
return err
}
return nil _, err = exec.Command("/bin/sh", "-c", cmdStr).Output()
if err != nil {
return err
}
return nil
} }
// ViewAllContainers returns all containers runnable and which can be built // ViewAllContainers returns all containers runnable and which can be built
func ViewAllContainers() (*DockerContainers, error) { func ViewAllContainers() (*DockerContainers, error) {
// Traverse the deploy path as per given in the config file // Traverse the deploy path as per given in the config file
config, err := config.ConfigInit(nil, nil) config, err := config.ConfigInit(nil, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
folders, err := ioutil.ReadDir(config.DockerContainers) folders, err := ioutil.ReadDir(config.DockerContainers)
if err != nil { if err != nil {
return nil, err return nil, err
} }
//Declare variable DockerContainers of type struct //Declare variable DockerContainers of type struct
var Containers *DockerContainers = new(DockerContainers) var Containers *DockerContainers = new(DockerContainers)
for _, f := range folders { for _, f := range folders {
if f.IsDir() { if f.IsDir() {
//Declare variable DockerContainer of type struct //Declare variable DockerContainer of type struct
var Container DockerContainer var Container DockerContainer
// Setting container name to deploy name // Setting container name to deploy name
Container.ContainerName = f.Name() Container.ContainerName = f.Name()
// Getting Description from file description.txt // Getting Description from file description.txt
Description, err := ioutil.ReadFile(config.DockerContainers + "/" + Container.ContainerName + "/description.txt") Description, err := ioutil.ReadFile(config.DockerContainers + "/" + Container.ContainerName + "/description.txt")
// if we os.Open returns an error then handle it // if we os.Open returns an error then handle it
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Get Description from description.txt // Get Description from description.txt
Container.ContainerDescription = string(Description) Container.ContainerDescription = string(Description)
Containers.DockerContainer = append(Containers.DockerContainer, Container) Containers.DockerContainer = append(Containers.DockerContainer, Container)
} }
} }
return Containers, nil return Containers, nil
} }
func print(rd io.Reader) error { func print(rd io.Reader) error {
var lastLine string var lastLine string
scanner := bufio.NewScanner(rd) scanner := bufio.NewScanner(rd)
for scanner.Scan() { for scanner.Scan() {
lastLine = scanner.Text() lastLine = scanner.Text()
} }
errLine := &ErrorLine{} errLine := &ErrorLine{}
json.Unmarshal([]byte(lastLine), errLine) json.Unmarshal([]byte(lastLine), errLine)
if errLine.Error != "" { if errLine.Error != "" {
return errors.New(errLine.Error) return errors.New(errLine.Error)
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
return err return err
} }
return nil return nil
} }
func OpenPortsFile(filename string) (*Ports, error) { func OpenPortsFile(filename string) (*Ports, error) {
buf, err := ioutil.ReadFile(filename) buf, err := ioutil.ReadFile(filename)
if err != nil { if err != nil {
return nil, err return nil, err
} }
c := &Ports{} c := &Ports{}
err = json.Unmarshal(buf, c) err = json.Unmarshal(buf, c)
if err != nil { if err != nil {
return nil, fmt.Errorf("in file %q: %v", filename, err) return nil, fmt.Errorf("in file %q: %v", filename, err)
} }
return c, nil return c, nil
}
// TemplateDockerContainer This function templates the docker container
// with the base docker image to use
func (d *DockerVM) TemplateDockerContainer() error {
err := d.CopyToTmpContainer()
if err != nil {
return err
}
// parses the site.yml file in the tmp directory
t, err := template.ParseFiles(d.ImagePath + "/" + d.TagName + "/Dockerfile")
if err != nil {
return err
}
// opens the output file
f, err := os.Create(d.ImagePath + "/" + d.TagName + "/Dockerfile")
if err != nil {
return err
}
image := d.BaseImage
// Pass in Docker Base Image
err = t.Execute(f, image)
if err != nil {
return err
}
return nil
}
// CopyToTmpContainer Creates a copy of the docker folder
func (d *DockerVM) CopyToTmpContainer() error {
// generate rand to UUID this is debug the ansible file if needed
id := uuid.New()
// copies the plugin to the tmp directory
err := copy.Copy(d.ImagePath+"/", d.LogsPath+id.String()+"_"+d.TagName)
if err != nil {
return err
}
// Set the plugin execution to the tmp location
d.TagName = id.String() + "_" + d.TagName
// removing slash
d.ImagePath = d.LogsPath[:len(d.LogsPath)-1]
return nil
} }

View File

@@ -1,43 +0,0 @@
package server
import (
"fmt"
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
"net"
"net/rpc"
)
const (
port = "8089"
)
type Listener int
type Docker struct {
docker *docker.DockerVM
}
// Starts container using RPC calls
func (l *Listener) StartContainer(reply *Docker) error {
vm, err := docker.BuildRunContainer(3, "false", "")
if err != nil {
return err
}
fmt.Printf("Receive: %v\n", vm)
*reply = Docker{vm}
return nil
}
func Rpc() {
rpcServer, err := net.ResolveTCPAddr("tcp", "0.0.0.0:"+port)
if err != nil {
fmt.Print(err)
}
inbound, err := net.ListenTCP("tcp", rpcServer)
if err != nil {
fmt.Print(err)
}
listener := new(Listener)
rpc.Register(listener)
rpc.Accept(inbound)
}

View File

@@ -1,239 +1,240 @@
package server package server
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable" "github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
"github.com/Akilan1999/p2p-rendering-computation/config" "github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/p2p" "github.com/Akilan1999/p2p-rendering-computation/p2p"
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp" "github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
"github.com/Akilan1999/p2p-rendering-computation/server/docker" "github.com/Akilan1999/p2p-rendering-computation/server/docker"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strconv" "strconv"
"time" "time"
) )
func Server() (*gin.Engine, error) { func Server() (*gin.Engine, error) {
r := gin.Default() r := gin.Default()
//Get Server port based on the config file //Get Server port based on the config file
config, err := config.ConfigInit(nil, nil) config, err := config.ConfigInit(nil, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// update IPTable with new port and ip address and update ip table // update IPTable with new port and ip address and update ip table
var ProxyIpAddr p2p.IpAddress var ProxyIpAddr p2p.IpAddress
var lowestLatencyIpAddress p2p.IpAddress var lowestLatencyIpAddress p2p.IpAddress
// Gets default information of the server // Gets default information of the server
r.GET("/server_info", func(c *gin.Context) { r.GET("/server_info", func(c *gin.Context) {
c.JSON(http.StatusOK, ServerInfo()) c.JSON(http.StatusOK, ServerInfo())
}) })
// Speed test with 50 mbps // Speed test with 50 mbps
r.GET("/50", func(c *gin.Context) { r.GET("/50", func(c *gin.Context) {
// Get Path from config // Get Path from config
c.File(config.SpeedTestFile) c.File(config.SpeedTestFile)
}) })
// Route build to do a speed test // Route build to do a speed test
r.GET("/upload", func(c *gin.Context) { r.GET("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file") file, _ := c.FormFile("file")
// Upload the file to specific dst. // Upload the file to specific dst.
// c.SaveUploadedFile(file, dst) // c.SaveUploadedFile(file, dst)
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
}) })
//Gets Ip Table from server node //Gets Ip Table from server node
r.POST("/IpTable", func(c *gin.Context) { r.POST("/IpTable", func(c *gin.Context) {
// Getting IPV4 address of client // Getting IPV4 address of client
var ClientHost p2p.IpAddress var ClientHost p2p.IpAddress
if p2p.Ip4or6(c.ClientIP()) == "version 6" { if p2p.Ip4or6(c.ClientIP()) == "version 6" {
ClientHost.Ipv6 = c.ClientIP() ClientHost.Ipv6 = c.ClientIP()
} else { } else {
ClientHost.Ipv4 = c.ClientIP() ClientHost.Ipv4 = c.ClientIP()
} }
// Variable to store IP table information // Variable to store IP table information
var IPTable p2p.IpAddresses var IPTable p2p.IpAddresses
// Receive file from POST request // Receive file from POST request
body, err := c.FormFile("json") body, err := c.FormFile("json")
if err != nil { if err != nil {
c.String(http.StatusOK, fmt.Sprint(err)) c.String(http.StatusOK, fmt.Sprint(err))
} }
// Open file // Open file
open, err := body.Open() open, err := body.Open()
if err != nil { if err != nil {
c.String(http.StatusOK, fmt.Sprint(err)) c.String(http.StatusOK, fmt.Sprint(err))
} }
// Open received file // Open received file
file, err := ioutil.ReadAll(open) file, err := ioutil.ReadAll(open)
if err != nil { if err != nil {
c.String(http.StatusOK, fmt.Sprint(err)) c.String(http.StatusOK, fmt.Sprint(err))
} }
json.Unmarshal(file, &IPTable) json.Unmarshal(file, &IPTable)
//Add Client IP address to IPTable struct //Add Client IP address to IPTable struct
IPTable.IpAddress = append(IPTable.IpAddress, ClientHost) IPTable.IpAddress = append(IPTable.IpAddress, ClientHost)
// Runs speed test to return only servers in the IP table pingable // Runs speed test to return only servers in the IP table pingable
err = IPTable.SpeedTestUpdatedIPTable() err = IPTable.SpeedTestUpdatedIPTable()
if err != nil { if err != nil {
c.String(http.StatusOK, fmt.Sprint(err)) c.String(http.StatusOK, fmt.Sprint(err))
} }
// Reads IP addresses from ip table // Reads IP addresses from ip table
IpAddresses, err := p2p.ReadIpTable() IpAddresses, err := p2p.ReadIpTable()
if err != nil { if err != nil {
c.String(http.StatusOK, fmt.Sprint(err)) c.String(http.StatusOK, fmt.Sprint(err))
} }
c.JSON(http.StatusOK, IpAddresses) c.JSON(http.StatusOK, IpAddresses)
}) })
// Starts docker container in server // Starts docker container in server
r.GET("/startcontainer", func(c *gin.Context) { r.GET("/startcontainer", func(c *gin.Context) {
// Get Number of ports to open and whether to use GPU or not // Get Number of ports to open and whether to use GPU or not
Ports := c.DefaultQuery("ports", "0") Ports := c.DefaultQuery("ports", "0")
GPU := c.DefaultQuery("GPU", "false") GPU := c.DefaultQuery("GPU", "false")
ContainerName := c.DefaultQuery("ContainerName", "") ContainerName := c.DefaultQuery("ContainerName", "")
var PortsInt int BaseImage := c.DefaultQuery("BaseImage", "")
var PortsInt int
// Convert Get Request value to int // Convert Get Request value to int
fmt.Sscanf(Ports, "%d", &PortsInt) fmt.Sscanf(Ports, "%d", &PortsInt)
// Creates container and returns-back result to // Creates container and returns-back result to
// access container // access container
resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName) resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName, BaseImage)
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
} }
// Ensures that FRP is triggered only if a proxy address is provided // Ensures that FRP is triggered only if a proxy address is provided
if ProxyIpAddr.Ipv4 != "" && c.Request.Host != "localhost:"+config.ServerPort && c.Request.Host != "0.0.0.0:"+config.ServerPort { if ProxyIpAddr.Ipv4 != "" && c.Request.Host != "localhost:"+config.ServerPort && c.Request.Host != "0.0.0.0:"+config.ServerPort {
resp, err = frp.StartFRPCDockerContainer(ProxyIpAddr.Ipv4, lowestLatencyIpAddress.ServerPort, resp) resp, err = frp.StartFRPCDockerContainer(ProxyIpAddr.Ipv4, lowestLatencyIpAddress.ServerPort, resp)
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
} }
fmt.Println(resp) fmt.Println(resp)
} }
c.JSON(http.StatusOK, resp) c.JSON(http.StatusOK, resp)
}) })
//Remove container //Remove container
r.GET("/RemoveContainer", func(c *gin.Context) { r.GET("/RemoveContainer", func(c *gin.Context) {
ID := c.DefaultQuery("id", "0") ID := c.DefaultQuery("id", "0")
if err := docker.StopAndRemoveContainer(ID); err != nil { if err := docker.StopAndRemoveContainer(ID); err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
} }
c.String(http.StatusOK, "success") c.String(http.StatusOK, "success")
}) })
//Show images available //Show images available
r.GET("/ShowImages", func(c *gin.Context) { r.GET("/ShowImages", func(c *gin.Context) {
resp, err := docker.ViewAllContainers() resp, err := docker.ViewAllContainers()
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
} }
c.JSON(http.StatusOK, resp) c.JSON(http.StatusOK, resp)
}) })
// Request for port no from Server with address // Request for port no from Server with address
r.GET("/FRPPort", func(c *gin.Context) { r.GET("/FRPPort", func(c *gin.Context) {
port, err := frp.StartFRPProxyFromRandom() port, err := frp.StartFRPProxyFromRandom()
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
} }
c.String(http.StatusOK, strconv.Itoa(port)) c.String(http.StatusOK, strconv.Itoa(port))
}) })
// If there is a proxy port specified // If there is a proxy port specified
// then starts the FRP server // then starts the FRP server
//if config.FRPServerPort != "0" { //if config.FRPServerPort != "0" {
// go frp.StartFRPProxyFromRandom() // go frp.StartFRPProxyFromRandom()
//} //}
// TODO check if IPV6 or Proxy port is specified // TODO check if IPV6 or Proxy port is specified
// if not update current entry as proxy address // if not update current entry as proxy address
// with appropriate port on IP Table // with appropriate port on IP Table
if config.BehindNAT == "True" { if config.BehindNAT == "True" {
// Remove nodes currently not pingable // Remove nodes currently not pingable
clientIPTable.RemoveOfflineNodes() clientIPTable.RemoveOfflineNodes()
table, err := p2p.ReadIpTable() table, err := p2p.ReadIpTable()
if err != nil { if err != nil {
return nil, err return nil, err
} }
var lowestLatency int64 var lowestLatency int64
// random large number // random large number
lowestLatency = 10000000 lowestLatency = 10000000
for i, _ := range table.IpAddress { for i, _ := range table.IpAddress {
// Checks if the ping is the lowest and if the following node is acting as a proxy // Checks if the ping is the lowest and if the following node is acting as a proxy
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" { //if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].NAT != "" { if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].NAT != "" {
lowestLatency = table.IpAddress[i].Latency.Milliseconds() lowestLatency = table.IpAddress[i].Latency.Milliseconds()
lowestLatencyIpAddress = table.IpAddress[i] lowestLatencyIpAddress = table.IpAddress[i]
} }
} }
// If there is an identified node // If there is an identified node
if lowestLatency != 10000000 { if lowestLatency != 10000000 {
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort) serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Create 3 second delay to allow FRP server to start // Create 3 second delay to allow FRP server to start
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
// Starts FRP as a client with // Starts FRP as a client with
proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, config.ServerPort, "") proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, config.ServerPort, "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
// updating with the current proxy address // updating with the current proxy address
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4 ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
ProxyIpAddr.ServerPort = proxyPort ProxyIpAddr.ServerPort = proxyPort
ProxyIpAddr.Name = config.MachineName ProxyIpAddr.Name = config.MachineName
ProxyIpAddr.NAT = "False" ProxyIpAddr.NAT = "False"
ProxyIpAddr.EscapeImplementation = "FRP" ProxyIpAddr.EscapeImplementation = "FRP"
// append the following to the ip table // append the following to the ip table
table.IpAddress = append(table.IpAddress, ProxyIpAddr) table.IpAddress = append(table.IpAddress, ProxyIpAddr)
// write information back to the IP Table // write information back to the IP Table
err = table.WriteIpTable() err = table.WriteIpTable()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// update ip table // update ip table
go func() error { go func() error {
err := clientIPTable.UpdateIpTableListClient() err := clientIPTable.UpdateIpTableListClient()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return err return err
} }
return nil return nil
}() }()
} }
} }
// Run gin server on the specified port // Run gin server on the specified port
go r.Run(":" + config.ServerPort) go r.Run(":" + config.ServerPort)
return r, nil return r, nil
} }