-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement grid-compose #1130
base: development
Are you sure you want to change the base?
implement grid-compose #1130
Changes from 12 commits
7503ba9
84cbd10
7f0d28b
9e70865
7d3cff0
905394b
40e67a2
9fcedd2
09d55e2
3b095a7
9e227e1
b0f3b22
4bf7aaf
352ef37
de9f63a
07c5da9
124fe56
bd2aa64
8ddab7b
deb6275
f21cf97
bf550b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
bin/* | ||
.pre-commit-config.yaml | ||
out | ||
full_example.yml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
test: | ||
@echo "Running Tests" | ||
go test -v ./... | ||
|
||
clean: | ||
rm ./bin -rf | ||
|
||
getverifiers: | ||
@echo "Installing golangci-lint" && go install github.com/golangci/golangci-lint/cmd/golangci-lint | ||
go mod tidy | ||
|
||
lint: | ||
@echo "Running $@" | ||
golangci-lint run -c ../.golangci.yml | ||
|
||
build: | ||
@echo "Running $@" | ||
@go build -ldflags=\ | ||
"-X 'github.com/threefoldtech/tfgrid-sdk-go/grid-compose/cmd.commit=$(shell git rev-parse HEAD)'\ | ||
-X 'github.com/threefoldtech/tfgrid-sdk-go/grid-compose/cmd.version=$(shell git tag --sort=-version:refname | head -n 1)'"\ | ||
-o bin/grid-compose main.go |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# Grid-Compose | ||
|
||
is a tool for running multi-vm applications on TFGrid defined using a Yaml formatted file. | ||
|
||
## Usage | ||
|
||
`REQUIRED` EnvVars: | ||
|
||
- `MNEMONIC`: your secret words | ||
- `NETWORK`: one of (dev, qa, test, main) | ||
|
||
```bash | ||
grid-compose [OPTIONS] [COMMAND] | ||
|
||
OPTIONS: | ||
-f, --file: path to yaml file, default is ./grid-compose.yaml | ||
|
||
COMMANDS: | ||
- version: shows the project version | ||
- up: deploy the app | ||
- down: cancel all deployments | ||
- ps: list deployments on the grid | ||
OPTIONS: | ||
- -v, --verbose: show full details of each deployment | ||
- -o, --output: redirects the output to a file given its path | ||
``` | ||
|
||
Export env vars using: | ||
|
||
```bash | ||
export MNEMONIC=your_mnemonics | ||
export NETWORK=working_network | ||
``` | ||
|
||
Run: | ||
|
||
```bash | ||
make build | ||
``` | ||
|
||
To use any of the commands, run: | ||
|
||
```bash | ||
./bin/grid-compose [COMMAND] | ||
``` | ||
|
||
For example: | ||
|
||
```bash | ||
./bin/grid-compose ps -f example/multiple_services_diff_network_3.yml | ||
``` | ||
|
||
## Usage For Each Command | ||
|
||
### up | ||
|
||
The up command deploys the services defined in the yaml file to the grid. | ||
|
||
Refer to the [cases](docs/cases.md) for more information on the cases supported. | ||
|
||
Refer to examples in the [examples](examples) directory to have a look at different possible configurations. | ||
|
||
```bash | ||
./bin/grid-compose up [OPTIONS] | ||
``` | ||
|
||
OPTIONS: | ||
|
||
- `-f, --file`: path to the yaml file, default is `./grid-compose.yaml` | ||
|
||
### down | ||
|
||
```bash | ||
./bin/grid-compose down [OPTIONS] | ||
``` | ||
|
||
OPTIONS: | ||
|
||
- `-f, --file`: path to the yaml file, default is `./grid-compose.yaml` | ||
|
||
### ps | ||
|
||
```bash | ||
./bin/grid-compose ps [FLAGS] [OPTIONS] | ||
``` | ||
|
||
OPTIONS: | ||
|
||
- `-f, --file`: path to the yaml file, default is `./grid-compose.yaml` | ||
- `-v, --verbose`: show full details of each deployment | ||
- `-o, --output`: redirects the output to a file given its path(in json format) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/rs/zerolog/log" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var downCmd = &cobra.Command{ | ||
Use: "down", | ||
Short: "cancel your project on the grid", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if err := app.Down(); err != nil { | ||
log.Fatal().Err(err).Send() | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(downCmd) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/rs/zerolog/log" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var psCmd = &cobra.Command{ | ||
Use: "ps", | ||
Short: "list deployments on the grid", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
flags := cmd.Flags() | ||
|
||
if err := app.Ps(cmd.Context(), flags); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. invoke the flags here, and pass to the method only the values it needs |
||
log.Fatal().Err(err).Send() | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
psCmd.PersistentFlags().BoolP("verbose", "v", false, "all information about deployed services") | ||
psCmd.PersistentFlags().StringP("output", "o", "", "output result to a file") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can drop this and simply use bash redirecting. |
||
rootCmd.AddCommand(psCmd) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package cmd | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/rs/zerolog" | ||
"github.com/rs/zerolog/log" | ||
"github.com/spf13/cobra" | ||
"github.com/threefoldtech/tfgrid-sdk-go/grid-compose/internal" | ||
) | ||
|
||
var ( | ||
app *internal.App | ||
configPath string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to avoid the global variable, we could add the app to the context. it will shared between the commands |
||
network string | ||
mnemonic string | ||
) | ||
|
||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
log.Fatal().Err(err).Send() | ||
} | ||
} | ||
|
||
// TODO: Validate command line arguments | ||
var rootCmd = &cobra.Command{ | ||
Use: "grid-compose", | ||
Short: "Grid-Compose is a tool for running multi-vm applications on TFGrid defined using a Yaml formatted file.", | ||
PersistentPreRun: func(cmd *cobra.Command, args []string) { | ||
var err error | ||
app, err = internal.NewApp(network, mnemonic, configPath) | ||
if err != nil { | ||
log.Fatal().Err(err).Send() | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
network = os.Getenv("NETWORK") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move getting the env to the Run in rootCmd |
||
mnemonic = os.Getenv("MNEMONIC") | ||
rootCmd.PersistentFlags().StringVarP(&configPath, "file", "f", "./grid-compose.yaml", "the grid-compose configuration file") | ||
|
||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/rs/zerolog/log" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var upCmd = &cobra.Command{ | ||
Use: "up", | ||
Short: "deploy application on the grid", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if err := app.Up(cmd.Context()); err != nil { | ||
log.Fatal().Err(err).Send() | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(upCmd) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Package cmd for parsing command line arguments | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
// set at build time | ||
var commit string | ||
var version string | ||
|
||
// versionCmd represents the version command | ||
var versionCmd = &cobra.Command{ | ||
Use: "version", | ||
Short: "Get latest build tag", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
fmt.Println(version) | ||
fmt.Println(commit) | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(versionCmd) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
These are most if not all the cases supported by the grid compose cli when deploying one or more service to the grid. | ||
|
||
## Single Service | ||
|
||
### Case 1 - Node ID Not Given + No Assigned Network | ||
|
||
This is probably the simplest case there is. | ||
|
||
- Filter the nodes based on the resources given to the service and choose a random one. | ||
- Generate a default network and assign it to the deployment. | ||
|
||
Refer to example [single_service_1.yml](../examples/single_service_1.yml) | ||
|
||
### Case 2 - Node ID Given + No Assigned Network | ||
|
||
- Simply use the the node id given to deploy the service. | ||
- (**CURRENT BEHAVIOR**) Return an error if node is not available | ||
- (**TODO BEHAVIOR**) If the available resources in the given node are less than what the service needs, filter the nodes and check if there is one that can be used. | ||
- If there is a node available, prompt the user if they would like to use it instead. | ||
- Generate a default network and assign it to the deployment. | ||
|
||
Refer to example [single_service_2.yml](../examples/single_service_2.yml) | ||
|
||
### Case 3 - Assigned Network | ||
|
||
- Either use the assigned node id or filter the nodes for an available node if no node id given. | ||
- Use the network assigned to the service when deploying. | ||
|
||
Refer to example [single_service_3.yml](../examples/single_service_3.yml) | ||
|
||
## Multiple Services | ||
|
||
Dealing with multiple services will depend on the networks assigned to each service. In a nutshell, it is assumed that **if two services are assigned the same network they are going to be in the same deployment, which means in the same node,** so failing to stick to this assumption will yield errors and no service will be deployed. | ||
|
||
### Same Network/No Network | ||
|
||
This is a common general case: Laying down services a user needs to deploy in the same node using a defined network or not defining any network at all. | ||
|
||
#### Case 1 - Node ID Given | ||
|
||
Essentially what is required is that at least one service is assigned a node id and automatically all the other services assigned to the same network will be deployed using this node. | ||
|
||
It is also possible to assign a node id to some of the services or even all of them, but keep in mind that **if two services running on the same network and each one is assigned a different node id, this will cause an error and nothing will be deployed.** | ||
|
||
#### Case 2 - No Node ID Given | ||
|
||
This is a more common case, the user mostly probably will not care to provide any node ids. In that case: | ||
|
||
- The node id will be filtered based on the total resources for the services provided. | ||
|
||
<br /> | ||
If all the services are assigned a network, then all of them will be deployed using that network. | ||
|
||
If no networks are defined, then all the services will use the **default generated network**. | ||
|
||
Refer to examples | ||
|
||
- [two_services_same_network_1.yml](../examples/two_services_same_network_1.yml) | ||
- [two_services_same_network_2.yml](../examples/two_services_same_network_2.yml) | ||
- [two_services_same_network_3.yml](../examples/two_services_same_network_3.yml) | ||
|
||
### Different Networks | ||
|
||
Simple divide the services into groups having the same network(given or generated) and deal with each group using the approached described in the previous [section](#same-networkno-network). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move registering commands to the init() in root.go