diff --git a/client/Iptable.go b/client/Iptable.go index 531c56b..ced9cd3 100644 --- a/client/Iptable.go +++ b/client/Iptable.go @@ -3,6 +3,8 @@ package client import ( "bytes" "encoding/json" + "fmt" + "git.sr.ht/~akilan1999/p2p-rendering-computation/config" "git.sr.ht/~akilan1999/p2p-rendering-computation/p2p" "io" "io/ioutil" @@ -12,17 +14,34 @@ import ( "path/filepath" ) -// Does the following to update it's IP table +type IP struct { + Query string +} + +// UpdateIpTable Does the following to update it's IP table func UpdateIpTable(IpAddress string) error { - resp, err := SendPostRequest("http://"+IpAddress+":8088/IpTable", - "/etc/p2p-rendering/ip_table.json", - "json") + config, err := config.ConfigInit() + if err != nil { + return err + } + + client := http.Client{} + + resp, err := UploadMultipartFile(client,"http://"+IpAddress+":8088/IpTable","json",config.IPTable) if err != nil { return err } + //resp, err := SendPostRequest("http://"+IpAddress+":8088/IpTable", + // config.IPTable, + // "json") + // + //if err != nil { + // return err + //} + var ipStruct p2p.IpAddresses json.Unmarshal(resp, &ipStruct) @@ -36,7 +55,7 @@ func UpdateIpTable(IpAddress string) error { return nil } -//updates IP tables (Default 3 hops) based on server information available +// UpdateIpTableListClient updates IP tables (Default 3 hops) based on server information available //on the ip tables func UpdateIpTableListClient() error { // Ensure that the IP Table has Node pingable @@ -49,7 +68,7 @@ func UpdateIpTableListClient() error { // duplication Addresses, err := p2p.ReadIpTable() - DoNotRead := Addresses + var DoNotRead p2p.IpAddresses // Run loop 3 times for i := 0; i < 3; i++ { @@ -59,11 +78,25 @@ func UpdateIpTableListClient() error { return err } + // Appending current machine public IP address as should not be there in IP Table + var PublicIP p2p.IpAddress + ip, err := CurrentPublicIP() + if err != nil { + return err + } + PublicIP.Ipv4 = ip + DoNotRead.IpAddress = append(DoNotRead.IpAddress, PublicIP) + // Updates IP table based on server IP table for j := range Addresses.IpAddress { - // Check if IP addresses is there in the struct DoNotRead Exists := false + + if PublicIP.Ipv4 == Addresses.IpAddress[j].Ipv4 { + Exists = true + } + + // Check if IP addresses is there in the struct DoNotRead for k := range DoNotRead.IpAddress { if DoNotRead.IpAddress[k].Ipv4 == Addresses.IpAddress[j].Ipv4 { Exists = true @@ -75,7 +108,6 @@ func UpdateIpTableListClient() error { if Exists { continue } - err = UpdateIpTable(Addresses.IpAddress[j].Ipv4) if err != nil { return err @@ -89,7 +121,8 @@ func UpdateIpTableListClient() error { return nil } -// Sends a file as a POST request. +// SendPostRequest Sends a file as a +//POST request. // Reference (https://stackoverflow.com/questions/51234464/upload-a-file-with-post-request-golang) func SendPostRequest (url string, filename string, filetype string) ([]byte,error) { file, err := os.Open(filename) @@ -132,4 +165,76 @@ func SendPostRequest (url string, filename string, filetype string) ([]byte,erro } return content, nil +} + +func UploadMultipartFile(client http.Client, uri, key, path string) ([]byte, error) { + body, writer := io.Pipe() + + req, err := http.NewRequest(http.MethodPost, uri, body) + if err != nil { + return nil, err + } + + mwriter := multipart.NewWriter(writer) + req.Header.Add("Content-Type", mwriter.FormDataContentType()) + + errchan := make(chan error) + + go func() { + defer close(errchan) + defer writer.Close() + defer mwriter.Close() + + w, err := mwriter.CreateFormFile(key, path) + if err != nil { + errchan <- err + return + } + + in, err := os.Open(path) + if err != nil { + errchan <- err + return + } + defer in.Close() + + if written, err := io.Copy(w, in); err != nil { + errchan <- fmt.Errorf("error copying %s (%d bytes written): %v", path, written, err) + return + } + + if err := mwriter.Close(); err != nil { + errchan <- err + return + } + }() + + resp, err := client.Do(req) + content, err := ioutil.ReadAll(resp.Body) + + if err != nil { + return nil, err + } + + return content, nil + +} + +// CurrentPublicIP Get Current Public IP address +func CurrentPublicIP() (string,error) { + req, err := http.Get("http://ip-api.com/json/") + if err != nil { + return "",err + } + defer req.Body.Close() + + body, err := ioutil.ReadAll(req.Body) + if err != nil { + return "",err + } + + var ip IP + json.Unmarshal(body, &ip) + + return ip.Query, nil } \ No newline at end of file diff --git a/cmd/action.go b/cmd/action.go index de03e0e..12b7287 100644 --- a/cmd/action.go +++ b/cmd/action.go @@ -16,7 +16,7 @@ var CliAction = func(ctx *cli.Context) error { } //Listing servers and also updates IP tables (Default 3 hops) - if ListServers { + if UpdateServerList { err := client.UpdateIpTableListClient() if err != nil { @@ -26,6 +26,10 @@ var CliAction = func(ctx *cli.Context) error { p2p.PrintIpTable() } + if ServerList { + p2p.PrintIpTable() + } + // Function called to stop and remove server from Docker if RemoveVM != "" && ID != "" { err := client.RemoveContianer(RemoveVM,ID) @@ -38,7 +42,6 @@ var CliAction = func(ctx *cli.Context) error { if CreateVM != "" { var PortsInt int - PortsInt = 0 if Ports != "" { // Convert Get Request value to int diff --git a/cmd/flags.go b/cmd/flags.go index b8abb56..c18b59e 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -6,14 +6,15 @@ import ( // Variables declared for CLI var ( - CreateVM string - Ports string - Mode string - RemoveVM string - ID string - Specs string - GPU bool - ListServers bool + CreateVM string + Ports string + Mode string + RemoveVM string + ID string + Specs string + GPU bool + UpdateServerList bool + ServerList bool ) var AppConfigFlags = []cli.Flag{ @@ -25,11 +26,17 @@ var AppConfigFlags = []cli.Flag{ EnvVars: []string{"P2P_MODE"}, Destination: &Mode, }, + &cli.BoolFlag{ + Name: "UpdateServerList", + Usage: "Update List of Server available based on servers iptables", + EnvVars: []string{"UPDATE_SERVER_LIST"}, + Destination: &UpdateServerList, + }, &cli.BoolFlag{ Name: "ListServers", Usage: "List servers which can render tasks", EnvVars: []string{"LIST_SERVERS"}, - Destination: &ListServers, + Destination: &ServerList, }, &cli.StringFlag{ Name: "CreateVM", @@ -53,7 +60,7 @@ var AppConfigFlags = []cli.Flag{ Name: "Ports", Usage: "Number of ports to open for the Docker Container", EnvVars: []string{"NUM_PORTS"}, - Destination: &ID, + Destination: &Ports, }, &cli.BoolFlag{ Name: "GPU", diff --git a/p2p/50.bin b/p2p/50.bin index 151a7c2..1a20dba 100644 Binary files a/p2p/50.bin and b/p2p/50.bin differ diff --git a/p2p/ip_table.json b/p2p/ip_table.json index 570b065..78cf758 100644 --- a/p2p/ip_table.json +++ b/p2p/ip_table.json @@ -1,10 +1,16 @@ { "ip_address": [ { - "ipv4": "localhost", - "latency": 14981051, - "download": 8142.122540206258, - "upload": 3578.766512629995 + "ipv4": "145.40.90.151", + "latency": 144024138, + "download": 6.124989686501195, + "upload": 3863.649528583081 + }, + { + "ipv4": "86.99.70.106", + "latency": 7972645, + "download": 87.32677875720803, + "upload": 6006.624976985241 } ] } \ No newline at end of file diff --git a/p2p/iptable.go b/p2p/iptable.go index 4bd3725..a6ba6e0 100644 --- a/p2p/iptable.go +++ b/p2p/iptable.go @@ -22,15 +22,14 @@ type IpAddress struct { Upload float64 `json:"upload"` } -// Read data from Ip tables from json file +// ReadIpTable Read data from Ip tables from json file func ReadIpTable()(*IpAddresses ,error){ // Get Path from config config, err := config.ConfigInit() if err != nil { return nil,err } - - jsonFile, err := os.Open(config.SpeedTestFile) + jsonFile, err := os.Open(config.IPTable) // if we os.Open returns an error then handle it if err != nil { return nil,err @@ -53,7 +52,7 @@ func ReadIpTable()(*IpAddresses ,error){ return &ipAddresses, nil } -// Write to IP table json file +// WriteIpTable Write to IP table json file func (i *IpAddresses) WriteIpTable() error { file, err := json.MarshalIndent(i, "", " ") if err != nil { @@ -66,7 +65,7 @@ func (i *IpAddresses) WriteIpTable() error { return err } - err = ioutil.WriteFile(config.SpeedTestFile, file, 0644) + err = ioutil.WriteFile(config.IPTable, file, 0644) if err != nil { return err } @@ -74,7 +73,7 @@ func (i *IpAddresses) WriteIpTable() error { return nil } -// Print Ip table data for Cli +// PrintIpTable Print Ip table data for Cli func PrintIpTable() error { table, err := ReadIpTable() diff --git a/p2p/speedtest.go b/p2p/speedtest.go index 5e724d1..43dc8c1 100644 --- a/p2p/speedtest.go +++ b/p2p/speedtest.go @@ -1,6 +1,6 @@ package p2p -// Runs a speed test and does updates IP tables accordingly +// SpeedTest Runs a speed test and does updates IP tables accordingly func (ip *IpAddresses)SpeedTest() error{ for i, _ := range ip.IpAddress { @@ -8,7 +8,7 @@ func (ip *IpAddresses)SpeedTest() error{ err := ip.IpAddress[i].PingTest() if err != nil { // Remove IP address of element not pingable - ip.IpAddress = append(ip.IpAddress[:i], ip.IpAddress[i+1:]...) + ip.IpAddress = remove(ip.IpAddress,i) // Proceed to next element in the array continue } @@ -33,7 +33,7 @@ func (ip *IpAddresses)SpeedTest() error{ return nil } -// Called when ip tables from client/server is also passed on +// SpeedTestUpdatedIPTable Called when ip tables from client/server is also passed on func (ip *IpAddresses)SpeedTestUpdatedIPTable() error{ targets, err := ReadIpTable() if err != nil { @@ -71,7 +71,7 @@ func (ip *IpAddresses)SpeedTestUpdatedIPTable() error{ return nil } -// Runs speed test in iptables locally only +// LocalSpeedTestIpTable Runs speed test in iptables locally only func LocalSpeedTestIpTable() error { targets, err := ReadIpTable() if err != nil { @@ -86,3 +86,8 @@ func LocalSpeedTestIpTable() error { return nil } +// Helper function to remove element from an array of a struct +func remove(s []IpAddress, i int) []IpAddress { + s[len(s)-1], s[i] = s[i], s[len(s)-1] + return s[:len(s)-1] +} diff --git a/server/docker/docker.go b/server/docker/docker.go index 3dfd142..b3e347b 100644 --- a/server/docker/docker.go +++ b/server/docker/docker.go @@ -145,52 +145,53 @@ func (d *DockerVM)imageBuild(dockerClient *client.Client) error { func (d *DockerVM)runContainer(dockerClient *client.Client) error{ ctx, _ := context.WithTimeout(context.Background(), time.Second*2000) - //Exposed ports for docker config file - 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 { - - Port, err := nat.NewPort("tcp",fmt.Sprint(d.Ports[i])) - if err != nil { - return err - } - - // Exposed Ports - ExposedPort[Port] = struct{}{} - - PortForwarding[Port] = []nat.PortBinding{ - { - HostIP: "0.0.0.0", - HostPort: fmt.Sprint(d.Ports[i]), - }, - } - } // 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 // implementation docker api does not support the flag "--gpu all" if d.GPU != "true" { + //Exposed ports for docker config file + 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 { + + Port, err := nat.NewPort("tcp",fmt.Sprint(d.Ports[i])) + if err != nil { + return err + } + + // Exposed Ports + ExposedPort[Port] = struct{}{} + + PortForwarding[Port] = []nat.PortBinding{ + { + HostIP: "0.0.0.0", + HostPort: fmt.Sprint(d.Ports[i]), + }, + } + } + config := &container.Config{ Image: d.TagName, Entrypoint: []string{"/dockerstartup/vnc_startup.sh", "/start"}, diff --git a/server/server.go b/server/server.go index 3fe0a6f..a7b90cb 100644 --- a/server/server.go +++ b/server/server.go @@ -44,10 +44,9 @@ func Server() error{ // Getting IPV4 address of client var ClientHost p2p.IpAddress ClientHost.Ipv4 = c.ClientIP() + // Variable to store IP table information var IPTable p2p.IpAddresses - //Add Client IP address to IPTable struct - IPTable.IpAddress = append(IPTable.IpAddress, ClientHost) // Receive file from POST request body, err := c.FormFile("json") @@ -69,6 +68,9 @@ func Server() error{ json.Unmarshal(file,&IPTable) + //Add Client IP address to IPTable struct + IPTable.IpAddress = append(IPTable.IpAddress, ClientHost) + // Runs speed test to return only servers in the IP table pingable err = IPTable.SpeedTestUpdatedIPTable() if err != nil {