Merge pull request #61 from Akilan1999/group

Group
This commit is contained in:
Akilan Selvacoumar
2021-08-13 23:17:19 +04:00
committed by GitHub
12 changed files with 752 additions and 75 deletions

2
.gitignore vendored
View File

@@ -14,4 +14,4 @@ p2p/iptable/
#ignore plugins added
plugin/deploy/
#ignore track container file
client/trackcontianers/
client/trackcontainers/

View File

@@ -5,6 +5,7 @@
2. [Reading server specifications](#reading-server-specifications)
3. [Client creating and removing container](#Client-creating-and-removing-container)
4. [Tracking Containers](#Tracking-Containers)
5. [Grouping Containers](#Grouping-Containers)
This section focuses in depth on how the client module works. The client module is incharge of communicating with
different servers based on the IP addresses provided to the user. The IP addresses are derived
@@ -57,3 +58,28 @@ show a sample structure of file ```trackcontainer.json```.
```
The default path to the container tracker is ```client/trackcontainers/trackcontainers.json```.
### Grouping Containers
When starting a set container possibility to be able to group them.
The benefit this would be that when executing plugins the group ID would be enough to execute
plugin in a set of containers. This provides the possibility to execute repetitive tasks in containers in
a single cli command. To store groups there is a file called ```grouptrackcontainer.json``` which tracks all
the groups currently present set by the client. The snippet below
show a sample structure of file ```grouptrackcontainer.json```.
```
{
"Groups": [
{
"ID": "grp<Random UUID>",
"TrackContainer": [{client.TrackContainers struct}]
}
]
}
```
The default path to the container tracker is ```client/trackcontainers/grouptrackcontainer.json```.
### Note:
The group id will be auto-generated and will have its own prefix in the start which will mostly be ```grp<UUID>```.
When a container is removed using the command. ```p2prc --rm <IP Address> --id <Container id>```. It will be automatically deleted
from the groups it exists in.

View File

@@ -147,6 +147,33 @@ p2prc --tc
p2prc --plugin <plugin name> --id <container id>
```
### Create group
```
p2prc --cgroup
```
### Add container to group
```
p2prc --group <group id> --id <container id>
```
### View groups
```
p2prc --groups
```
### View specific group
```
p2prc --group <group id>
```
### Delete container from group
```
p2prc --rmcgroup --group <group id> --id <contianer id>
```
### Delete entire group
```
p2prc --rmgroup <group id>
```
[read more on grouping containers](ClientImplementation.md#Grouping-Containers)
<br>
--------------

View File

@@ -0,0 +1,282 @@
package client
import (
"encoding/json"
"errors"
"git.sr.ht/~akilan1999/p2p-rendering-computation/config"
"github.com/google/uuid"
"io/ioutil"
"os"
)
// Groups Data Structure type
type Groups struct {
GroupList []*Group `json:"Groups"`
}
// Group Information about a single group
type Group struct {
ID string `json:"ID"`
TrackContainerList []*TrackContainer `json:"TrackContainer"`
// Sneaky as required only when removing the element
// Set when GetGroup function is called
index int
}
// CreateGroup Creates a new group to add a set of track containers
func CreateGroup() (*Group, error){
// Creating variable of type new group
var NewGroup Group
// Generate new UUID for group ID
id := uuid.New()
// Add new group id and prepend with the string "grp"
// The reason this is done is to differentiate between a
// group ID and docker container ID
NewGroup.ID = "grp" + id.String()
// Adding the new group to the
// GroupTrackContainer File
err := NewGroup.AddGroupToFile()
if err != nil {
return nil, err
}
return &NewGroup,nil
}
// RemoveGroup Removes group based on the group ID provided
func RemoveGroup(GroupID string) error {
// Read group information from the
//grouptrackcontainer json file
groups, err := ReadGroup()
if err != nil {
return err
}
// Gets Group struct based on group ID
// provided
group, err := GetGroup(GroupID)
if err != nil {
return err
}
// Remove Group struct from the groups variable
groups.GroupList = append(groups.GroupList[:group.index], groups.GroupList[group.index+1:]...)
// Write new groups to the grouptrackcontainer json file
err = groups.WriteGroup()
if err != nil {
return err
}
return nil
}
// AddContainerToGroup Adds container information to the Group based on the Group ID
func AddContainerToGroup(ContainerID string, GroupID string) (*Group, error) {
// Gets container information based on container ID provided
containerInfo, err := GetContainerInformation(ContainerID)
if err != nil {
return nil, err
}
// Gets group information based on the group ID provided
group, err := GetGroup(GroupID)
if err != nil {
return nil, err
}
// Adds container information the group
group.AddContainer(containerInfo)
// Get Groups information from reading the grouptrackcontainer.json file
groups, err := ReadGroup()
if err != nil {
return nil, err
}
// Updating specific element in the group list with the added container
groups.GroupList[group.index] = group
// Write groups information on the grouptrackcontainer.json file
err = groups.WriteGroup()
if err != nil {
return nil, err
}
return group, nil
}
// RemoveContainerGroup Remove Container from the group ID specified
func RemoveContainerGroup(ContainerID string, GroupID string) (*Group,error) {
// Get container information based on container ID provided
containerInfo, err := GetContainerInformation(ContainerID)
if err != nil {
return nil,err
}
// Gets group information based on the group ID provided
group, err := GetGroup(GroupID)
if err != nil {
return nil,err
}
// Remove container from the appropriate group
err = group.RemoveContainerGroup(containerInfo)
if err != nil {
return nil,err
}
// Get Groups information from reading the grouptrackcontainer.json file
groups, err := ReadGroup()
if err != nil {
return nil, err
}
// Updating specific element in the group list with the remove container
groups.GroupList[group.index] = group
// Write groups information on the grouptrackcontainer.json file
err = groups.WriteGroup()
if err != nil {
return nil, err
}
return group, nil
}
// RemoveContainerGroups Remove Container from groups (i.e which ever groups has information
// about that container). This is mostly called when a container is deleted or removed from
// the tracked container list
func RemoveContainerGroups(ContainerID string) error {
// Get container information based on container ID provided
containerInfo, err := GetContainerInformation(ContainerID)
if err != nil {
return err
}
// Get Groups information from reading the grouptrackcontainer.json file
groups, err := ReadGroup()
if err != nil {
return err
}
// Removes container information from all groups it is found in
err = groups.RemoveContainerGroups(containerInfo)
if err != nil {
return err
}
// Write groups information on the grouptrackcontainer.json file
err = groups.WriteGroup()
if err != nil {
return err
}
return nil
}
// GetGroup Gets group information based on
// group id provided
func GetGroup(GroupID string) (*Group,error) {
// Read group information from the
//grouptrackcontainer json file
groups, err := ReadGroup()
if err != nil {
return nil, err
}
// Iterate through the set of groups and
// if the group ID matches then return it
for i, group := range groups.GroupList {
if group.ID == GroupID {
group.index = i
return group, nil
}
}
return nil,errors.New("Group not found. ")
}
// AddGroupToFile Adds Group struct to the GroupTrackContainer File
func (grp *Group) AddGroupToFile() error {
// Gets all group information from the
// GroupTrackContainer JSON file
groups, err := ReadGroup()
if err != nil {
return err
}
// Appending the newly created group
groups.GroupList = append(groups.GroupList, grp)
// Writing Group information to the GroupTrackContainer
// JSON file
err = groups.WriteGroup()
if err != nil {
return err
}
return nil
}
// ReadGroup Function reads grouptrackcontainers.json and converts
// result to Groups
func ReadGroup() (*Groups,error) {
// Get Path from config
config, err := config.ConfigInit()
if err != nil {
return nil,err
}
jsonFile, err := os.Open(config.GroupTrackContainersPath)
// if we os.Open returns an error then handle it
if err != nil {
return nil,err
}
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
// read our opened xmlFile as a byte array.
byteValue, _ := ioutil.ReadAll(jsonFile)
// we initialize our Users array
var groups Groups
// we unmarshal our byteArray which contains our
// jsonFile's content into 'users' which we defined above
json.Unmarshal(byteValue, &groups)
return &groups, nil
}
// WriteGroup Function to write type Groups to the grouptrackcontainers.json file
func (grp *Groups)WriteGroup() error {
file, err := json.MarshalIndent(grp, "", " ")
if err != nil {
return err
}
// Get Path from config
config, err := config.ConfigInit()
if err != nil {
return err
}
// Writes to the appropriate file
err = ioutil.WriteFile(config.GroupTrackContainersPath, file, 0644)
if err != nil {
return err
}
return nil
}
// AddContainer Adds a container to the Tracked container list of the group
func (grp *Group)AddContainer(Container *TrackContainer) error {
grp.TrackContainerList = append(grp.TrackContainerList, Container)
return nil
}
// RemoveContainerGroup Removes container information from the group
func (grp *Group)RemoveContainerGroup(Container *TrackContainer) error {
// Iterating through all container in the Group of Tracked Container
for i, container := range grp.TrackContainerList {
// If the container ID matches then remove the container from the group
if container.Id == Container.Id {
grp.TrackContainerList = append(grp.TrackContainerList[:i], grp.TrackContainerList[i+1:]...)
}
}
return nil
}
// RemoveContainerGroups removes container found in all groups
func (grp *Groups)RemoveContainerGroups(Container *TrackContainer) error {
// Iterating through all groups
for i,group := range grp.GroupList {
// Removes the container in the following group
// if it exists
err := group.RemoveContainerGroup(Container)
if err != nil {
return err
}
// Set group information to list groups
grp.GroupList[i] = group
}
return nil
}

View File

@@ -0,0 +1,267 @@
package client
import (
"fmt"
"git.sr.ht/~akilan1999/p2p-rendering-computation/server/docker"
"testing"
)
// Testing out if a new group is getting created
func TestCreateGroup(t *testing.T) {
group, err := CreateGroup()
if err != nil {
fmt.Println(err)
t.Fail()
}
PrettyPrint(group)
}
// Testing if the group gets removed when a
// group ID is provided
func TestRemoveGroup(t *testing.T) {
// Creates a new group
group, err := CreateGroup()
if err != nil {
fmt.Println(err)
t.Fail()
}
// Removes the new group
// it created
err = RemoveGroup(group.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
}
// Testing if container information is added
// to the created group
func TestAddContainerToGroup(t *testing.T) {
// Creates a new group
group, err := CreateGroup()
if err != nil {
fmt.Println(err)
t.Fail()
}
// Creating and adding the container to the
// tracked list
container1 ,err := docker.BuildRunContainer(0,"false","")
if err != nil {
fmt.Println(err)
t.Fail()
}
// Testing the AddTrackContainer Function and adding the first container created
err = AddTrackContainer(container1,"0.0.0.0")
if err != nil {
// Killing docker container created
err = docker.StopAndRemoveContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
fmt.Println(err)
t.Fail()
}
// Adds container information to the group
Group, err := AddContainerToGroup(container1.ID,group.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
PrettyPrint(Group)
// Killing docker container created
err = docker.StopAndRemoveContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
// Removing container 1 from the tracked list
err = RemoveTrackedContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
// Removes the new group
// it created
err = RemoveGroup(group.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
}
// Testing if the container information is removed from the group
func TestGroup_RemoveContainerGroup(t *testing.T) {
// Creates a new group
group, err := CreateGroup()
if err != nil {
fmt.Println(err)
t.Fail()
}
// Creating and adding the container to the
// tracked list
container1 ,err := docker.BuildRunContainer(0,"false","")
if err != nil {
fmt.Println(err)
t.Fail()
}
// Testing the AddTrackContainer Function and adding the first container created
err = AddTrackContainer(container1,"0.0.0.0")
if err != nil {
// Killing docker container created
err = docker.StopAndRemoveContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
fmt.Println(err)
t.Fail()
}
// Adds container information to the group
Group, err := AddContainerToGroup(container1.ID,group.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
fmt.Println("Container added")
PrettyPrint(Group)
// Removing docker container from the group
Group, err = RemoveContainerGroup(container1.ID,group.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
fmt.Println("Container removed")
PrettyPrint(Group)
// Killing docker container created
err = docker.StopAndRemoveContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
// Removing container 1 from the tracked list
err = RemoveTrackedContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
// Removes the new group
// it created
err = RemoveGroup(group.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
}
// Testing that container are removed from all
// created groups
// Scenario:
// - Create 2 groups
// - Add Container information to each group
// - Remove Container information from each group
func TestGroups_RemoveContainerGroups(t *testing.T) {
// Creates a new group
group, err := CreateGroup()
if err != nil {
fmt.Println(err)
t.Fail()
}
// Created another group assigned to variable group 1
group1, err := CreateGroup()
if err != nil {
fmt.Println(err)
t.Fail()
}
// Creating and adding the container to the
// tracked list
container1 ,err := docker.BuildRunContainer(0,"false","")
if err != nil {
fmt.Println(err)
t.Fail()
}
// Testing the AddTrackContainer Function and adding the first container created
err = AddTrackContainer(container1,"0.0.0.0")
if err != nil {
// Killing docker container created
err = docker.StopAndRemoveContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
fmt.Println(err)
t.Fail()
}
// Adds container information to the group
Group, err := AddContainerToGroup(container1.ID,group.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
fmt.Println("Container added")
PrettyPrint(Group)
// Adds container information to the group
Group1, err := AddContainerToGroup(container1.ID,group1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
fmt.Println("Container added")
PrettyPrint(Group1)
// Removing docker container from the group
err = RemoveContainerGroups(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
// Killing docker container created
err = docker.StopAndRemoveContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
// Removing container 1 from the tracked list
err = RemoveTrackedContainer(container1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
// Removes the new group
// it created
err = RemoveGroup(group.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
// Removes the new group
// it created
err = RemoveGroup(group1.ID)
if err != nil {
fmt.Println(err)
t.Fail()
}
}

View File

@@ -12,7 +12,7 @@ import (
// TrackContainers This struct stores arrays of current containers running
type TrackContainers struct {
TrackcontianerList []TrackContainer `json:"TrackContainer"`
TrackContainerList []TrackContainer `json:"TrackContainer"`
}
// TrackContainer Stores information of current containers
@@ -63,7 +63,7 @@ func AddTrackContainer(d *docker.DockerVM,ipAddress string) error {
if &trackContainer == nil {
return errors.New("trackContainer variable is nil")
}
trackContainers.TrackcontianerList = append(trackContainers.TrackcontianerList, trackContainer)
trackContainers.TrackContainerList = append(trackContainers.TrackContainerList, trackContainer)
// write modified information to the tracked json file
data,err := json.MarshalIndent(trackContainers, "", "\t")
@@ -86,12 +86,12 @@ func RemoveTrackedContainer(id string) error {
return err
}
// Getting tracked container struct
trackedContianers, err := ReadTrackContainers(config.TrackContainersPath)
trackedContainers, err := ReadTrackContainers(config.TrackContainersPath)
// Storing index of element to remove
var removeElement int
removeElement = -1
for i := range trackedContianers.TrackcontianerList {
if trackedContianers.TrackcontianerList[i].Id == id {
for i := range trackedContainers.TrackContainerList {
if trackedContainers.TrackContainerList[i].Id == id {
removeElement = i
break
}
@@ -101,10 +101,10 @@ func RemoveTrackedContainer(id string) error {
return errors.New("Container ID not found in the tracked list")
}
// Remove the detected element from the struct
trackedContianers.TrackcontianerList = append(trackedContianers.TrackcontianerList[:removeElement], trackedContianers.TrackcontianerList[removeElement+1:]...)
trackedContainers.TrackContainerList = append(trackedContainers.TrackContainerList[:removeElement], trackedContainers.TrackContainerList[removeElement+1:]...)
// write modified information to the tracked json file
data,err := json.MarshalIndent(trackedContianers, "", "\t")
data,err := json.MarshalIndent(trackedContainers, "", "\t")
if err != nil {
return err
}
@@ -156,7 +156,7 @@ func GetContainerInformation(ID string) (*TrackContainer, error) {
}
// Iterating through all tracked containers to get the container information
// of the ID passed through the function parameter
for _, container := range CurrentContainers.TrackcontianerList {
for _, container := range CurrentContainers.TrackContainerList {
if container.Container.ID == ID {
return &container, nil
}

View File

@@ -97,6 +97,11 @@ func RemoveContianer(IP string,ID string) error {
fmt.Println("success")
}
// Remove container from groups it exists in
err = RemoveContainerGroups(ID)
if err != nil {
return err
}
// Remove container created from the tracked list
err = RemoveTrackedContainer(ID)
if err != nil {

View File

View File

@@ -1,41 +0,0 @@
{
"TrackContainer": [
{
"ID": "858912730fb34f3cce38ef6d405e04519e44f50c2a496cd400e75aaa0def3c80",
"Container": {
"SSHUsername": "master",
"SSHPassword": "password",
"ID": "858912730fb34f3cce38ef6d405e04519e44f50c2a496cd400e75aaa0def3c80",
"TagName": "p2p-ubuntu",
"ImagePath": "/home/akilan/Documents/p2p-rendering-computation/server/docker/containers/docker-ubuntu-sshd/",
"Ports": {
"Port": [
{
"PortName": "SSH",
"InternalPort": 22,
"Type": "tcp",
"ExternalPort": 44269,
"Description": "SSH Port"
},
{
"PortName": "NoVNC",
"InternalPort": 5901,
"Type": "tcp",
"ExternalPort": 40725,
"Description": "NoVNC port"
},
{
"PortName": "NoVNC",
"InternalPort": 6081,
"Type": "tcp",
"ExternalPort": 40053,
"Description": "NoVNC port"
}
]
},
"GPU": "false"
},
"IpAddress": "0.0.0.0"
}
]
}

View File

@@ -181,6 +181,69 @@ var CliAction = func(ctx *cli.Context) error {
}
// Executing function to create new group
// Creates new group and outputs JSON file
if CreateGroup {
group, err := client.CreateGroup()
if err != nil {
return err
}
client.PrettyPrint(group)
}
// Actions to be performed when the
// group flag is called
// --group <Group ID>
if Group != "" {
// Remove container from group based on group ID provided
// --rmcgroup --id <contianer id>
if RemoveContainerGroup && ID != "" {
group, err := client.RemoveContainerGroup(ID, Group)
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(group)
}
} else if ID != "" { // Add container to group based on group ID provided
// --id <Container ID>
group, err := client.AddContainerToGroup(ID,Group)
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(group)
}
} else { // View all information about current group
group, err := client.GetGroup(Group)
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(group)
}
}
}
// Execute function to remove entire group
// when remove group flag is called
// --rmgroup
if RemoveGroup != "" {
err := client.RemoveGroup(RemoveGroup)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Group Removed")
}
}
// Execute Function to view all groups
if Groups {
groups, err := client.ReadGroup()
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(groups)
}
}
return nil
}

View File

@@ -6,23 +6,28 @@ import (
// Variables declared for CLI
var (
AddServer string
ViewImages string
CreateVM string
ContainerName string
Ports string
Server bool
RemoveVM string
ID string
Specs string
GPU bool
UpdateServerList bool
ServerList bool
SetDefaultConfig bool
NetworkInterface bool
ViewPlugin bool
TrackedContainers bool
ExecutePlugin string
AddServer string
ViewImages string
CreateVM string
ContainerName string
Ports string
Server bool
RemoveVM string
ID string
Specs string
GPU bool
UpdateServerList bool
ServerList bool
SetDefaultConfig bool
NetworkInterface bool
ViewPlugin bool
TrackedContainers bool
ExecutePlugin string
CreateGroup bool
Group string
Groups bool
RemoveContainerGroup bool
RemoveGroup string
)
var AppConfigFlags = []cli.Flag{
@@ -147,4 +152,39 @@ var AppConfigFlags = []cli.Flag{
EnvVars: []string{"EXECUTE_PLUGIN"},
Destination: &ExecutePlugin,
},
&cli.BoolFlag{
Name: "CreateGroup",
Aliases: []string{"cgroup"},
Usage: "Creates a new group",
EnvVars: []string{"CREATE_GROUP"},
Destination: &CreateGroup,
},
&cli.StringFlag{
Name: "Group",
Aliases: []string{"group"},
Usage: "group flag with argument group ID",
EnvVars: []string{"GROUP"},
Destination: &Group,
},
&cli.BoolFlag{
Name: "Groups",
Aliases: []string{"groups"},
Usage: "View all groups",
EnvVars: []string{"GROUPS"},
Destination: &Groups,
},
&cli.BoolFlag{
Name: "RemoveContainerGroup",
Aliases: []string{"rmcgroup"},
Usage: "Remove specific container in the group",
EnvVars: []string{"REMOVE_CONTAINER_GROUP"},
Destination: &RemoveContainerGroup,
},
&cli.StringFlag{
Name: "RemoveGroup",
Aliases: []string{"rmgroup"},
Usage: "Removes the entire group",
EnvVars: []string{"REMOVE_GROUP"},
Destination: &RemoveGroup,
},
}

View File

@@ -21,14 +21,15 @@ var (
)
type Config struct {
IPTable string
DockerContainers string
DefaultDockerFile string
SpeedTestFile string
IPV6Address string
PluginPath string
TrackContainersPath string
ServerPort string
IPTable string
DockerContainers string
DefaultDockerFile string
SpeedTestFile string
IPV6Address string
PluginPath string
TrackContainersPath string
ServerPort string
GroupTrackContainersPath string
//NetworkInterface string
//NetworkInterfaceIPV6Index int
}
@@ -88,6 +89,12 @@ func SetDefaults() error {
return err
}
//Creates a copy of trackcontainers.json in the appropriate directory
err = Copy("client/grouptrackcontainers.json","client/trackcontainers/grouptrackcontainers.json")
if err != nil {
return err
}
//Setting default paths for the config file
defaults["IPTable"] = defaultPath + "p2p/iptable/ip_table.json"
@@ -97,6 +104,7 @@ func SetDefaults() error {
defaults["IPV6Address"] = ""
defaults["PluginPath"] = defaultPath + "plugin/deploy"
defaults["TrackContainersPath"] = defaultPath + "client/trackcontainers/trackcontainers.json"
defaults["GroupTrackContainersPath"] = defaultPath + "client/trackcontainers/grouptrackcontainers.json"
defaults["ServerPort"] = "8088"
//defaults["NetworkInterface"] = "wlp0s20f3"
//defaults["NetworkInterfaceIPV6Index"] = "2"