From 2a7d8e154d7e60b3c25ec8b83712c7d96b3407b5 Mon Sep 17 00:00:00 2001 From: Akilan Selvacoumar Date: Sun, 3 Oct 2021 17:18:03 +0400 Subject: [PATCH 1/3] plugin copied to tmp and executed from there --- plugin/plugin.go | 58 +++++++++++++++++++++++++++++++++---------- plugin/plugin_test.go | 3 ++- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/plugin/plugin.go b/plugin/plugin.go index 06145e4..d883122 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -6,6 +6,7 @@ import ( "fmt" "git.sr.ht/~akilan1999/p2p-rendering-computation/client" "git.sr.ht/~akilan1999/p2p-rendering-computation/config" + "github.com/google/uuid" "gopkg.in/yaml.v2" "io/ioutil" "strconv" @@ -14,6 +15,7 @@ import ( "github.com/apenella/go-ansible/pkg/options" "github.com/apenella/go-ansible/pkg/playbook" "github.com/apenella/go-ansible/pkg/stdoutcallback/results" + "github.com/otiai10/copy" ) // Plugins Array of all plugins detected @@ -25,6 +27,7 @@ type Plugins struct { type Plugin struct { FolderName string PluginDescription string + path string Execute []*ExecuteIP } @@ -106,6 +109,12 @@ func RunPlugin(pluginName string ,IPAddresses []*ExecuteIP) (*Plugin,error) { if plugin.FolderName == pluginName { plugindetected = plugin plugindetected.Execute = IPAddresses + // Get Execute plugin path from config file + config, err := config.ConfigInit() + if err != nil { + return nil, err + } + plugindetected.path = config.PluginPath break } } @@ -113,6 +122,14 @@ func RunPlugin(pluginName string ,IPAddresses []*ExecuteIP) (*Plugin,error) { if plugindetected == nil { return nil, errors.New("Plugin not detected") } + + + // Create copy of the plugin the tmp directory + // To ensure we execute the plugin from there + err = plugindetected.CopyToTmpPlugin() + if err != nil { + return nil, err + } // Executing the plugin err = plugindetected.ExecutePlugin() @@ -125,21 +142,16 @@ func RunPlugin(pluginName string ,IPAddresses []*ExecuteIP) (*Plugin,error) { // ExecutePlugin Function to execute plugins that are called func (p *Plugin) ExecutePlugin() error { - // Get Execute plugin path from config file - config, err:= config.ConfigInit() - if err != nil { - return err - } // Run ip address to execute ansible inside for _,execute := range p.Execute { // Modify ansible hosts before executing - err = execute.ModifyHost(p,config.PluginPath) + err := execute.ModifyHost(p) if err != nil { return err } - err = execute.RunAnsible(p,config.PluginPath) + err = execute.RunAnsible(p) if err != nil { return err } @@ -150,13 +162,13 @@ func (p *Plugin) ExecutePlugin() error { } // RunAnsible Executes based on credentials on the struct -func (e *ExecuteIP)RunAnsible(p *Plugin,path string) error { +func (e *ExecuteIP)RunAnsible(p *Plugin) error { ansiblePlaybookConnectionOptions := &options.AnsibleConnectionOptions{ User: "master", } ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{ - Inventory: path + "/" + p.FolderName + "/hosts", + Inventory: p.path + "/" + p.FolderName + "/hosts", ExtraVars: map[string]interface{}{"host_key_checking":"false"}, } @@ -165,7 +177,7 @@ func (e *ExecuteIP)RunAnsible(p *Plugin,path string) error { } playbook := &playbook.AnsiblePlaybookCmd{ - Playbooks: []string{path + "/" + p.FolderName + "/site.yml"}, + Playbooks: []string{p.path + "/" + p.FolderName + "/site.yml"}, ConnectionOptions: ansiblePlaybookConnectionOptions, PrivilegeEscalationOptions: ansiblePlaybookPrivilegeEscalationOptions, Options: ansiblePlaybookOptions, @@ -185,8 +197,8 @@ func (e *ExecuteIP)RunAnsible(p *Plugin,path string) error { } // ModifyHost adds IP address , port no to the config file -func (e *ExecuteIP)ModifyHost(p *Plugin, path string) error { - host,err := ReadHost(path + "/" + p.FolderName + "/hosts") +func (e *ExecuteIP)ModifyHost(p *Plugin) error { + host,err := ReadHost(p.path + "/" + p.FolderName + "/hosts") if err != nil { return err } @@ -209,7 +221,7 @@ func (e *ExecuteIP)ModifyHost(p *Plugin, path string) error { if err != nil { return err } - err = ioutil.WriteFile(path + "/" + p.FolderName + "/hosts",data,0777) + err = ioutil.WriteFile(p.path + "/" + p.FolderName + "/hosts",data,0777) if err != nil { return err } @@ -301,3 +313,23 @@ func CheckRunPlugin(PluginName string, ID string) error { return nil } + +// CopyToTmpPlugin This function would ensure that we create a copy of the +// plugin in the tmp directory, and it would be executed +// from there. This due to the reason of automating port allocation +// when running plugins +func (p *Plugin)CopyToTmpPlugin() 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(p.path+"/"+p.FolderName, "/tmp/"+ id.String() + "_" + p.FolderName) + if err != nil { + return err + } + + // Set the plugin execution to the tmp location + p.path = "/tmp" + p.FolderName = id.String() + "_" + p.FolderName + + return nil +} diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go index bf51944..dd4cb2a 100644 --- a/plugin/plugin_test.go +++ b/plugin/plugin_test.go @@ -80,12 +80,13 @@ func TestExecuteIP_ModifyHost(t *testing.T) { } //Set plugin name plugin.FolderName = "TestAnsible" + plugin.path = Config.PluginPath //Test IP 1 configuration testip.IPAddress = "0.0.0.0" testip.SSHPortNo = "41289" - err = testip.ModifyHost(&plugin,Config.PluginPath) + err = testip.ModifyHost(&plugin) if err != nil { fmt.Println(err) t.Fail() From 9d8303d66cc91f077c2705b55c1239c748213541 Mon Sep 17 00:00:00 2001 From: Akilan Selvacoumar Date: Sun, 3 Oct 2021 22:13:45 +0400 Subject: [PATCH 2/3] add functionality to automatically allocate ports to a plugin --- plugin/plugin.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/plugin/plugin.go b/plugin/plugin.go index d883122..78773eb 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -9,7 +9,9 @@ import ( "github.com/google/uuid" "gopkg.in/yaml.v2" "io/ioutil" + "os" "strconv" + "text/template" "github.com/apenella/go-ansible/pkg/execute" "github.com/apenella/go-ansible/pkg/options" @@ -33,6 +35,7 @@ type Plugin struct { // ExecuteIP IP Address to execute Ansible instruction type ExecuteIP struct { + ContainerID string IPAddress string SSHPortNo string Success bool @@ -150,7 +153,11 @@ func (p *Plugin) ExecutePlugin() error { if err != nil { return err } - + // sets the ports to the plugin folder + err = p.AutoSetPorts(execute.ContainerID) + if err != nil { + return err + } err = execute.RunAnsible(p) if err != nil { return err @@ -244,7 +251,7 @@ func ReadHost(filename string) (*Host, error) { return c, nil } -// RunPluginContainer Runs ansible plugin based on plugin name and contianer name which +// RunPluginContainer Runs ansible plugin based on plugin name and container name which // is derived from the tracked containers file func RunPluginContainer(PluginName string, ContainerID string) error { // Gets container information based on container ID @@ -269,6 +276,8 @@ func RunPluginContainer(PluginName string, ContainerID string) error { } // IP address of the container ExecuteIP.IPAddress = ContainerInformation.IpAddress + // Set container ID to ExecutorIP + ExecuteIP.ContainerID = ContainerInformation.Id // Append IP to list of executor IP ExecuteIPs = append(ExecuteIPs, &ExecuteIP) // Run plugin to execute plugin @@ -333,3 +342,39 @@ func (p *Plugin)CopyToTmpPlugin() error { return nil } + +// AutoSetPorts Automatically maps free ports to site.yml file +func (p *Plugin)AutoSetPorts(containerID string) error { + container , err := client.GetContainerInformation(containerID) + if err != nil { + return err + } + // variable that would have a list of ports + // to be allocated to the plugin system + var ports []int + // setting all external ports available in an array + for _, port := range container.Container.Ports.PortSet { + if port.InternalPort == port.ExternalPort { + ports = append(ports, port.ExternalPort) + } + } + // parses the site.yml file in the tmp directory + t, err := template.ParseFiles(p.path + "/" + p.FolderName + "/site.yml") + if err != nil { + return err + } + // opens the output file + f, err := os.Create(p.path + "/" + p.FolderName + "/site.yml") + if err != nil { + return err + } + // sends the ports to the site.yml file to populate them + err = t.Execute(f,ports) + if err != nil { + return err + } + + return nil + + +} From 91b15e3bd71d664e5aa38343ec8ead5cb2e9e7aa Mon Sep 17 00:00:00 2001 From: Akilan Selvacoumar Date: Sun, 3 Oct 2021 23:05:56 +0400 Subject: [PATCH 3/3] added docs --- Docs/PluginImplementation.md | 50 +++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/Docs/PluginImplementation.md b/Docs/PluginImplementation.md index 1dcf2a9..a261edd 100644 --- a/Docs/PluginImplementation.md +++ b/Docs/PluginImplementation.md @@ -4,6 +4,8 @@ 2. [Site.yml](#site-File-Template) 3. [Host](#hosts-file) 4. [Description](#description-file) +5. [Automatic port allocations](#automatic-port-allocations) +6. [Sample plugins implemented](#sample-plugins-implemented) ## Introduction @@ -84,4 +86,50 @@ Ex: When the flag ```--ViewPlugins``` or ```--vp``` is called ] } -``` \ No newline at end of file +``` + +## Automatic port allocations +P2PRC would be in-charge to set to the ports to various TCP ports +opened. Due to this implementation the plugin being executed is +copied to the tmp directory with a unique UUID. +``` +Command: ls /tmp +output: Semantic _ +2e6d76c4-0ed1-4b55-9385-79a58d4f0492_p2prc-vscode-browser +7b631e08-62ee-4c1c-a2a4-c05857b9aa7d_p2prc-vscode-browser +``` +Once the copy of the plugin is added to the /tmp directory +the site.yml file inside the appropriate yaml is modified +with the appropriate ports assigned to the container. + +### Ex: +1. Create container called c1 with an automatic generated TCP port + 3313 (external) - 3313 (internal) +2. Assumption of plugin p1 exists. p1 has one server which needs to + be mapped to a free open TCP port in container c1. Below shows + an implementation of a sample site.yml file. +``` +--- +- hosts: all + tasks: + - name: start vscode code server + shell: sh server.sh 0.0.0.0:{{index . 0}} +``` +Notice there is the following {{index . 0}}. {{index . 0}} does not belong to +Ansible but rather is a way to mention where to add the external free port +of the container. We use the golang [template library](https://pkg.go.dev/text/template) +to parse and populate the site.yml with the appropriate open ports. An array of ints +which consists of open free ports are sent to the site.yml. 0 in {{index . 0}} refers +to the index in the int array passed on. + +After the port is automatically it's ready to run ! +``` +--- +- hosts: all + tasks: + - name: start vscode code server + shell: sh server.sh 0.0.0.0:3313 +``` + +### Sample plugins implemented: +- [VSCode Plugin](https://github.com/Akilan1999/p2prc-vscode-browser)