# Infra testing tool

## Prerequisites

### Dependencies
In order to use the infra testing tool you need a handful of other tools installed.
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) to manage AWS ressources, e.g. : run / stop servers
- [Packer](https://learn.hashicorp.com/tutorials/packer/get-started-install-cli) to create the Berty AMI (OS image for AWS servers)
- [Terraform](https://www.terraform.io/downloads.html) to provision infrastructure

**Note** : depending on how much infrastructure you want to generate and launch on AWS, you might need to increase your ElasticIP service quota. The default is 5 (meaning you could only have 5 nodes). If you want more, visit [this link](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-limit).

#### Example with `brew` on macOS
```bash
brew install awscli packer terraform
aws configure #Then enter ID, token, region, etc.
```

### Install client
```bash
make install.client
```

### Build AMI (Amazon Machine Image)
To speed up the tool considerably we build an AMI beforehand, so our cloud instances don't have to build the Berty CLI from source every time they get launched.
This also allows us to use instances with much less memory.

If this is your first time using the tool, or you want to rebuild the AMI you need to run the following command:
```bash
make update_ami
```

Knowing that you can override the following variables:
- `AWS_REGION` is the [AWS region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html#Concepts.RegionsAndAvailabilityZones.Regions) where the AMI will be built
- `GITHUB_REMOTE` is Github remote from which the code will be used to build the AMI
- `GITHUB_BRANCH` is Github branch from which the code will be used to build the AMI
- `SERVER_GO_VERSION` is the Golang version used to build the `berty` and `berty-infra-server` binaries within the AMI

This command will start building the machine images. This could take roughly 15 minutes.
When Packer has completed you can continue to the next step.

## Usage

### Generate config
This command generates the underlying *infrastructure as code* as well as a state file.
You can find these in the folder `infraState`, but they shouldn't be manually changed.
The flag `-f` points to your yaml configuration file.
```bash
infra generate -f conf.yaml
```

### Deploy infrastructure
This command will take the `infraState/main.tf` file and deploy it to AWS as described.
This command is **idempotent**, with the same underlying state: regardless of how many times you run it, the outcome will always be the same.
```bash
infra deploy
```
Depending on the size of the config, this could take a while.
### Destroy infrastructure
If something went wrong, or you just want to destroy all infrastructure generated by `deploy`, you can use this command to destroy it.
infra destroy
This command is **idempotent**, with the same underlying state: regardless of how many times you run it, the outcome will always be the same.
```
infra destroy
```
Depending on the deployed infrastructure, this could take a while.


### List running instances
This command will list all instances along with their name, type, id and IP.
This is great for debugging.
```bash
infra getIps
```

# Config
This is an example of a working config files
```yaml
peer:
    - name: test peers 1
      amount: 2
      reliability: 10,5
      groups:
          - name: message group
            tests:
                - type: text
                  size: 4KB
                  interval: 10
                  amount: 15
                - type: media
                  size: 40KB
                  interval: 50
                  amount: 3
      connections:
          - to: internet
            protocol: tcp
          - to: lan_1
            protocol: quic
      routers:
          - type: rdvp
            address: test rdvp
          - type: relay
            address: test relay

rdvp:
    - name: test rdvp
      amount: 1
      connections:
          - to: internet
            protocol: tcp

relay:
    - name: test relay
      amount: 3
      reliability: 20,15
      connections:
          - to: internet
            protocol: tcp
          - to: lan_1
            protocol: ws

bootstrap:
    - name: test bs
      amount: 1
      connections:
          - to: internet
            protocol: tcp
          - to: lan_1
            protocol: tcp
      routers:
          - type: relay
            address: test relay

settings:
    region: eu-west-3
    keyPairName: key_name
```
There are 5 categories of instances:
- peer
- rdvp
- instance
- bootstrap
- replication server

They can be placed in any order, the tool wil automatically calculate the dependencies and instantiate them in the right order.

## Name
Each nodeGroup needs a name. This can be anything, but it's best to keep it descriptive of what it represents.
The name will be propagated down to the individual nodes, but they will have a random suffix.

## Amount
This is an integer bigger than 0 defining how many nodes should be in the nodeGroup.
When `amount` is 0, there might be unexpected behaviour from the config parser building the network stack.
For this reason it's best to comment out unused infrastructure opposed to setting the amount to 0.
Each node inside the same nodegroup will have identical behaviour/config. The only difference is the name (different suffix), IP, tags, etc.
For example if you add a group to a nodeGroup, all nodes inside the nodeGroup will be part of this group.
Same with a router, if you add a RDVP to a nodeGroup, all nodes inside the nodeGroup will be connected to the same RDVP.

## Reliability
Defines their uptime. Some examples:
```
120,10 -> has 1/10 odds the node disconnects for 120 seconds
60,2 -> has 1/2 odds the node disconnects for 60 seconds
0,0 -> the node never disconnects
```


## Groups
This can only be used on **peer**s and **replication server**s.
### Name
Each group has a name. This can be anything.
### Tests
#### type
This has to be either **text** or **media**
#### size
This defines the size of the message. Example: 10KB, 200KB, 40MB, 4GB.
Although not recommended, it is possible to send large text/image messages.
#### interval
This is the interval between each sent message per node in seconds. Example: 15 -> will wait 15 seconds after sending a message before sending another one.
### amount
This is the amount of messages that will be sent during the test.

## Connections
The only reserved "destination" is `internet`. Any peer/type with the destination `internet` will be exposed to the internet.
Other than that you are free to name your destination groups however you like. Any peers/types with the same destination will be located in the same subnet/will be able to talk to eachother.

## Routers
This can only be used on **peer**s, **replication server**s and **bootstrap**s.
### type
There exist 3 types of routers: **rdvp**, **relay** and **bootstrap**.
The type has to be either one of these to work.
### address
The address of a router can be either the name of the router nodeGroup (defined in the config) or an IPFS compliant multi address.
This has support for multiple multi addresses at once separated by comma. If the named router nodeGroup has more than one node, it will automatically add all the nodes' multi address in that field.

# Settings
At the bottom of the config you have the option to configure the region and a key. Like this
```yaml
settings:
    region: eu-west-3
    keyPairName: berty_key
```
The `region` must be a valid AWS region.
Take note you might have to rebuild the AMI with packer in this region as AMI's are region specific.

If you want to add an ssh keypair so you can connect to the nodes once they are connected, you can.
Make a keypair and use the name in the `keyPairName` field. Find out how [here](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair).
