From 8466e2d1ca86eb19c204b05e7e39844ef487a2fb Mon Sep 17 00:00:00 2001 From: Akilan Selvacoumar Date: Wed, 9 Jun 2021 16:43:59 +0400 Subject: [PATCH 1/3] added code to detect docker containers --- config/config.go | 13 +++-- .../docker-ubuntu-sshd/description.txt | 1 + server/docker/docker.go | 57 ++++++++++++++++++- server/docker/docker_test.go | 11 +++- server/rpc.go | 3 +- server/server.go | 11 +++- 6 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 server/docker/containers/docker-ubuntu-sshd/description.txt diff --git a/config/config.go b/config/config.go index b30a11d..c51d04a 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,8 @@ var ( defaultPath string defaults = map[string]interface{}{ "IPTable": "/etc/p2p-rendering/ip_table.json", - "DockerFile": "/home/akilan/Documents/p2prendering/p2p-redering-computation/server/docker/containers/docker-ubuntu-sshd/", + "DockerContainers": "/home/akilan/Documents/p2prendering/p2p-redering-computation/server/docker/containers/", + "DefaultDockerFile": "/home/akilan/Documents/p2prendering/p2p-redering-computation/server/docker/containers/docker-ubuntu-sshd/", "SpeedTestFile":"/etc/p2p-rendering/50.bin", } configName = "config" @@ -19,9 +20,10 @@ var ( ) type Config struct { - IPTable string - DockerFile string - SpeedTestFile string + IPTable string + DockerContainers string + DefaultDockerFile string + SpeedTestFile string } // Exists reports whether the named file or directory exists. @@ -45,7 +47,8 @@ func SetDefaults() error { //Setting default paths for the config file defaults["IPTable"] = defaultPath + "p2p/ip_table.json" - defaults["DockerFile"] = defaultPath + "server/docker/containers/docker-ubuntu-sshd/" + defaults["DefaultDockerFile"] = defaultPath + "server/docker/containers/docker-ubuntu-sshd/" + defaults["DockerContainers"] = defaultPath + "server/docker/containers/" defaults["SpeedTestFile"] = defaultPath + "p2p/50.bin" //Paths to search for config file diff --git a/server/docker/containers/docker-ubuntu-sshd/description.txt b/server/docker/containers/docker-ubuntu-sshd/description.txt new file mode 100644 index 0000000..dc5b3fa --- /dev/null +++ b/server/docker/containers/docker-ubuntu-sshd/description.txt @@ -0,0 +1 @@ +Simple Ubuntu 20.04 image \ No newline at end of file diff --git a/server/docker/docker.go b/server/docker/docker.go index 10dd606..20ffbda 100644 --- a/server/docker/docker.go +++ b/server/docker/docker.go @@ -16,6 +16,7 @@ import ( "github.com/lithammer/shortuuid" "github.com/phayes/freeport" "io" + "io/ioutil" "os/exec" "time" ) @@ -33,6 +34,15 @@ type DockerVM struct { GPU string `json:"GPU"` } +type DockerContainers struct { + DockerContainer []DockerContainer `json:"DockerContainer"` +} + +type DockerContainer struct { + ContainerName string `json:"DockerContainerName"` + ContainerDescription string `json:"ContainerDescription"` +} + type ErrorLine struct { Error string `json:"error"` ErrorDetail ErrorDetail `json:"errorDetail"` @@ -44,7 +54,7 @@ type ErrorDetail struct { var dockerRegistryUserID = "" -func BuildRunContainer(NumPorts int, GPU string) (*DockerVM,error) { +func BuildRunContainer(NumPorts int, GPU string, ContainerName string) (*DockerVM,error) { //Docker Struct Variable var RespDocker *DockerVM = new(DockerVM) @@ -81,7 +91,7 @@ func BuildRunContainer(NumPorts int, GPU string) (*DockerVM,error) { if err != nil { return nil,err } - RespDocker.ImagePath = config.DockerFile + RespDocker.ImagePath = config.DefaultDockerFile // Gets docker information from env variables cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) @@ -238,7 +248,7 @@ func (d *DockerVM)runContainer(dockerClient *client.Client) error{ return nil } -// StopAndRemoveContainer TODO: Implement and remove docker instance running +// StopAndRemoveContainer // Stop and remove a container // Reference (https://gist.github.com/frikky/e2efcea6c733ea8d8d015b7fe8a91bf6) func StopAndRemoveContainer(containername string) error { @@ -266,6 +276,47 @@ func StopAndRemoveContainer(containername string) error { return nil } +// ViewAllContainers returns all containers runnable and which can be built +func ViewAllContainers() (*DockerContainers, error){ + // Traverse the folder path as per given in the config file + config, err := config.ConfigInit() + if err != nil { + return nil,err + } + + folders, err := ioutil.ReadDir(config.DockerContainers) + if err != nil { + return nil, err + } + + //Declare variable DockerContainers of type struct + var Containers *DockerContainers = new(DockerContainers) + + for _, f := range folders { + if f.IsDir() { + fmt.Print(f.Name()) + //Declare variable DockerContainer of type struct + var Container DockerContainer + + // Setting container name to folder name + Container.ContainerName = f.Name() + // Getting Description from file description.txt + Description, err := ioutil.ReadFile(config.DockerContainers + "/" + Container.ContainerName + "/description.txt") + // if we os.Open returns an error then handle it + if err != nil { + return nil, err + } + + // Get Description from description.txt + Container.ContainerDescription = string(Description) + + Containers.DockerContainer = append(Containers.DockerContainer, Container) + } + } + + return Containers,nil +} + func print(rd io.Reader) error { var lastLine string diff --git a/server/docker/docker_test.go b/server/docker/docker_test.go index 50f39b7..53921e2 100644 --- a/server/docker/docker_test.go +++ b/server/docker/docker_test.go @@ -7,7 +7,7 @@ import ( func TestDocker(t *testing.T) { //TODO overwrite with custom docker paths - resp,err := BuildRunContainer(2,"true") + resp,err := BuildRunContainer(2,"true","") if err != nil { t.Error(err) @@ -15,3 +15,12 @@ func TestDocker(t *testing.T) { fmt.Print(resp.VNCPort) } + +func TestViewAllContainers(t *testing.T) { + _,err := ViewAllContainers() + + if err != nil { + t.Error(err) + } + +} diff --git a/server/rpc.go b/server/rpc.go index eb8efad..cdd21f4 100644 --- a/server/rpc.go +++ b/server/rpc.go @@ -19,8 +19,7 @@ type Docker struct { // Starts container using RPC calls func (l *Listener) StartContainer( reply *Docker) error { - fmt.Print("here") - vm, err := docker.BuildRunContainer(3,"false") + vm, err := docker.BuildRunContainer(3,"false","") if err != nil { return err } diff --git a/server/server.go b/server/server.go index b0b11d5..354c392 100644 --- a/server/server.go +++ b/server/server.go @@ -104,7 +104,7 @@ func Server() error{ // Creates container and returns back result to // access container - resp, err := docker.BuildRunContainer(PortsInt,GPU) + resp, err := docker.BuildRunContainer(PortsInt,GPU,"") if err != nil { c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) @@ -122,6 +122,15 @@ func Server() error{ c.String(http.StatusOK, "success") }) + //Show images avaliable + r.GET("/ShowImages", func(c *gin.Context) { + resp, err := docker.ViewAllContainers() + if err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) + } + c.JSON(http.StatusOK, resp) + }) + // Future feature /*r.GET("/create_vm/:virtualization", func(c *gin.Context) { virtualization := c.Param("virtualization") From 14bceec3cc585a223d9435d44b2bb5aa15ac4acd Mon Sep 17 00:00:00 2001 From: Akilan Selvacoumar Date: Wed, 9 Jun 2021 23:59:46 +0400 Subject: [PATCH 2/3] added cli command view containers and implementation also complete --- client/container.go | 27 +++++++++++++++++++++++++++ cmd/action.go | 11 +++++++++++ cmd/flags.go | 8 ++++++++ server/server.go | 2 +- 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/client/container.go b/client/container.go index f37d945..9e57def 100644 --- a/client/container.go +++ b/client/container.go @@ -65,6 +65,33 @@ func RemoveContianer(IP string,ID string) error { return nil } +// ViewContainers This function displays all containers available on server side +func ViewContainers(IP string)(*docker.DockerContainers, error){ + // Passes URL with route /ShowImages + URL := "http://" + IP + ":" + serverPort + "/ShowImages" + resp, err := http.Get(URL) + if err != nil { + return nil,err + } + + // Convert response to byte value + byteValue, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil,err + } + + // Create variable for result response type + var Result docker.DockerContainers + + // Adds byte value to docker.DockerContainers struct + json.Unmarshal(byteValue, &Result) + if err != nil { + return nil,err + } + + return &Result, nil +} + // PrintStartContainer Prints results Generated container func PrintStartContainer(d *docker.DockerVM){ fmt.Println("ID : " + fmt.Sprint(d.ID)) diff --git a/cmd/action.go b/cmd/action.go index 2b97c5c..62022fd 100644 --- a/cmd/action.go +++ b/cmd/action.go @@ -31,6 +31,7 @@ var CliAction = func(ctx *cli.Context) error { p2p.PrintIpTable() } + // Add provided IP to the IP table if AddServer != "" { res, err := p2p.ReadIpTable() if err != nil { @@ -52,6 +53,16 @@ var CliAction = func(ctx *cli.Context) error { } + // Displays all images available on the server side + if ViewImages != "" { + imageRes, err := client.ViewContainers(ViewImages) + + if err != nil { + fmt.Print(err) + } + client.PrettyPrint(imageRes) + } + // Function called to stop and remove server from Docker if RemoveVM != "" && ID != "" { err := client.RemoveContianer(RemoveVM,ID) diff --git a/cmd/flags.go b/cmd/flags.go index 138ab34..2b5a97f 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -7,6 +7,7 @@ import ( // Variables declared for CLI var ( AddServer string + ViewImages string CreateVM string Ports string Mode string @@ -46,6 +47,12 @@ var AppConfigFlags = []cli.Flag{ EnvVars: []string{"ADD_SERVER"}, Destination: &AddServer, }, + &cli.StringFlag{ + Name: "ViewImages", + Usage: "View images available on the server IP address", + EnvVars: []string{"VIEW_IMAGES"}, + Destination: &ViewImages, + }, &cli.StringFlag{ Name: "CreateVM", Usage: "Creates Docker container on the selected server", @@ -82,6 +89,7 @@ var AppConfigFlags = []cli.Flag{ EnvVars: []string{"SPECS"}, Destination: &Specs, }, + &cli.BoolFlag{ Name: "SetDefaultConfig", Usage: "Sets a default configuration file", diff --git a/server/server.go b/server/server.go index 354c392..e166c1c 100644 --- a/server/server.go +++ b/server/server.go @@ -102,7 +102,7 @@ func Server() error{ // Convert Get Request value to int fmt.Sscanf(Ports, "%d", &PortsInt) - // Creates container and returns back result to + // Creates container and returns-back result to // access container resp, err := docker.BuildRunContainer(PortsInt,GPU,"") From ad9a1c96992fb8982eaca6e9eec716ca48efcc5f Mon Sep 17 00:00:00 2001 From: Akilan Selvacoumar Date: Thu, 10 Jun 2021 01:42:16 +0400 Subject: [PATCH 3/3] added functionality to specify container to run --- client/container.go | 4 ++-- cmd/action.go | 3 ++- cmd/flags.go | 7 +++++++ server/docker/docker.go | 16 ++++++++++++++++ server/server.go | 3 ++- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/client/container.go b/client/container.go index 9e57def..b4ca8f2 100644 --- a/client/container.go +++ b/client/container.go @@ -19,9 +19,9 @@ var client = http.Client{} // StartContainer Start container using REST api Implementation // From the selected server IP address // TODO: Test cases for this function -func StartContainer(IP string, NumPorts int, GPU bool) (*docker.DockerVM ,error) { +func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string) (*docker.DockerVM ,error) { // Passes URL with number of TCP ports to allocated and to give GPU access to the docker container - URL := "http://" + IP + ":" + serverPort + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + URL := "http://" + IP + ":" + serverPort + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName resp, err := http.Get(URL) if err != nil { return nil,err diff --git a/cmd/action.go b/cmd/action.go index 62022fd..9785fe4 100644 --- a/cmd/action.go +++ b/cmd/action.go @@ -81,7 +81,8 @@ var CliAction = func(ctx *cli.Context) error { fmt.Sscanf(Ports, "%d", &PortsInt) } - imageRes, err := client.StartContainer(CreateVM,PortsInt,GPU) + // Calls function to do Api call to start the container on the server side + imageRes, err := client.StartContainer(CreateVM,PortsInt,GPU,ContainerName) if err != nil { fmt.Print(err) diff --git a/cmd/flags.go b/cmd/flags.go index 2b5a97f..fc6c4fe 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -9,6 +9,7 @@ var ( AddServer string ViewImages string CreateVM string + ContainerName string Ports string Mode string RemoveVM string @@ -59,6 +60,12 @@ var AppConfigFlags = []cli.Flag{ EnvVars: []string{"CREATE_VM"}, Destination: &CreateVM, }, + &cli.StringFlag{ + Name: "ContainerName", + Usage: "Specifying the container run on the server side", + EnvVars: []string{"CONTAINER_NAME"}, + Destination: &ContainerName, + }, &cli.StringFlag{ Name: "RemoveVM", Usage: "Stop and Remove Docker container", diff --git a/server/docker/docker.go b/server/docker/docker.go index 20ffbda..7b53652 100644 --- a/server/docker/docker.go +++ b/server/docker/docker.go @@ -93,6 +93,22 @@ func BuildRunContainer(NumPorts int, GPU string, ContainerName string) (*DockerV } RespDocker.ImagePath = config.DefaultDockerFile + if ContainerName != "" { + Containers, err := ViewAllContainers() + if err != nil { + return nil,err + } + for _, dockerContainer := range Containers.DockerContainer { + if dockerContainer.ContainerName == ContainerName { + RespDocker.ImagePath = config.DockerContainers + ContainerName + "/" + break + } + } + if RespDocker.ImagePath == config.DefaultDockerFile { + return nil, errors.New("Container " + ContainerName + " does not exist in the server") + } + } + // Gets docker information from env variables cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { diff --git a/server/server.go b/server/server.go index e166c1c..7f847ff 100644 --- a/server/server.go +++ b/server/server.go @@ -97,6 +97,7 @@ func Server() error{ // Get Number of ports to open and whether to use GPU or not Ports := c.DefaultQuery("ports","0") GPU := c.DefaultQuery("GPU","false") + ContainerName := c.DefaultQuery("ContainerName","") var PortsInt int // Convert Get Request value to int @@ -104,7 +105,7 @@ func Server() error{ // Creates container and returns-back result to // access container - resp, err := docker.BuildRunContainer(PortsInt,GPU,"") + resp, err := docker.BuildRunContainer(PortsInt,GPU,ContainerName) if err != nil { c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))