# Introduction to the Twingate Python CLI

The Twingate Python CLI is a fully featured CLI tool utilising the Twingate GraphQL APIs.

### Open Source Contribution

The python CLI tool is an Open Source project developed and maintained outside of our product engineering teams. For support regarding this tool please visit the [GitHub issues page](https://github.com/Twingate-Labs/Twingate-CLI/issues).

The **Python Command Line Interface** wraps around the **Twingate GraphQL APIs** and is designed to automate several administrative functions otherwise available in the Admin Panel including (but not limited to):

- list / show / add / remove / update for Resources
- list / show / update trust for Devices
- list / show / add users / remove users / add resources / remove resources / create / delete / assign policy for Groups
- list / show / rename / generate tokens for Connectors
- list / show for Users
- list / show / create / delete / add resources / remove resources for Service Accounts
- show / create / revoke / delete / rename Service Account Keys
- list / show for Remote Networks
- list / show / assign groups to Policy

It requires the following:

- [python 3](https://www.python.org/downloads/)
- a common python library called [pandas](https://pandas.pydata.org/docs/getting_started/install.html)

### Finding the Command Line Interface

You can find the latest Python Command Line Interface on [GitHub](https://github.com/Twingate-Labs/Twingate-CLI).

## Getting Started

All you need to do in order to get started is to **clone the GitHub repository** mentioned above on your own machine.

Once done, open a **Terminal window** and navigate into the folder containing the CLI and run the following command: `python3 ./tgcli.py auth list`

If it returns an empty list, you are all set. If it returns an error, _it will likely be due to a missing python library_. Make sure to install it on your system and retry the command:

```text
python3 ./tgcli.py auth list
['']
```

## CLI Basics

The Command Line Interface is designed for people that have better things to do than memorizing lists of possible parameters.

The most important thing to know is that **no matter what parameter(s) you are passing to the CLI, you can always use `-h` to get a full list of contextual options**.

For instance, if you are getting started, you can run the CLI with no option other than `-h`:

```text
myhost % python3 ./tgcli.py -h
usage: tgcli.py [-h] [-v] [-s SESSIONNAME] [-f OUTPUTFORMAT]
                {auth,device,connector,user,group,resource,network,account} ...

positional arguments:
  {auth,device,connector,user,group,resource,network,account}

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -s SESSIONNAME, --session SESSIONNAME
                        Session Name
  -f OUTPUTFORMAT, --format OUTPUTFORMAT
                        Output Format <JSON,CSV,DF>
```

This tells us that the **types of objects** we can pass to the CLI are, among others:

- device
- connector
- resource
- etc.

So what if we want to figure out what the CLI can do for the **resource** objects? You guessed it: simply pass the object type (“resource”) and `-h`:

```text
myhost % python3 ./tgcli.py resource -h
usage: tgcli.py resource [-h] {list,show,create,delete} ...

positional arguments:
  {list,show,create,delete}

optional arguments:
  -h, --help            show this help message and exit
```

This now tells us that we can use the following **operations** on the **resource** object type:

- list
- show
- create
- delete

Great! Let’s take a look at the parameters needed if we want to apply the operation **list** on the **resource** object type:

```text
myhost % python3 ./tgcli.py resource list -h
usage: tgcli.py resource list [-h]

optional arguments:
  -h, --help  show this help message and exit
```

This looks promising: there are no parameter (other than `-h`) needed for this operation. We should now be able to list all resources in our environment.

Let’s try it:

```text
myhost % python3 ./tgcli.py resource list
usage: tgcli.py [-h] [-v] [-s SESSIONNAME] [-f OUTPUTFORMAT] {auth,device,connector,user,group,resource,network,account} ...
tgcli.py: error: no session name passed
```

It did not work and the CLI returned an error message complaining about _no session name passed_. Why? Simply because we have not yet authenticated the CLI against our tenant & API Key so the CLI does not know where to retrieve the information from.

This is where a very special **CLI object type** comes in: **auth**.

## CLI Authentication

Let’s apply the same `-h` logic to our auth object:

```text
myhost % python3 ./tgcli.py auth -h
usage: tgcli.py auth [-h] {login,logout,list} ...

positional arguments:
  {login,logout,list}

optional arguments:
  -h, --help           show this help message and exit
```

It looks like we can use three operations on the **auth** object:

- login (creates a new session)
- logout (remove an existing session)
- list (lists all available sessions)

Let’s take a look at the options required for the **login** operation:

```text
myhost % python3 ./tgcli.py auth login -h
usage: tgcli.py auth login [-h] [-a APIKEY] [-s SESSIONNAME] [-t TENANT]

optional arguments:
  -h, --help            show this help message and exit
  -a APIKEY, --apikey APIKEY
                        API Key
  -s SESSIONNAME, --session SESSIONNAME
                        Session Name (Optional)
  -t TENANT, --tenant TENANT
                        Twingate Network Tenant
```

It looks like there are 3 parameters to pass, 1 of which is Optional (`-s`). By now, we already know both our API Key and our Tenant name, so let’s run this command with the mandatory parameters (replace _mytenant_ and _mytoken_ with your own values):

```text
myhost % python3 ./tgcli.py auth login -t mytenant -a mytoken
Token Stored in session: OrangeElk
```

Perfect, we now have a session name we can use for all other CLI calls: this will ensure the CLI uses the right token & tenant name without having to re-authenticate for every single command.

### Using a Custom Session Name

You can specify the Session Name you want to use by using the `-s` option instead of letting it generate a random name for you.

Let’s go back to our CLI command to retrieve the list of resources and let’s add the `-s` option with **OrangeElk** as a value for it:

```text
myhost % python3 ./tgcli.py -s OrangeElk resource list
{
  "data": {
    "resources": {
      "edges": [
        {
          "node": {
            "id": "UmVzb3VyY2U6MjU3Mg==",
            "remoteNetwork": {
              "name": "AWS"
            },
            ...
```

Excellent! Our CLI now returns the full list of Twingate Resources defined in our environment.

## CLI Output Formatting

Since the CLI wraps around the Twingate GraphQL APIs, it returns responses in **JSON format** by default. JSON is great and easy to process programmatically, unfortunately it _isn’t very readable for humans_ and _isn’t very practical if you want to process the output using an OS Shell scripting language_.

This is why the CLI offers 3 separate output formats:

- JSON (default)
- CSV (easy to process programmatically with bash or powershell)
- DF (short for dataframes, a human-readable table format)

Here is the same output in **CSV**:

```text
myhost % python3 ./tgcli.py -s OrangeElk -f CSV resource list
node.id,node.remoteNetwork.name,node.address.type,node.address.value,node.protocols.allowIcmp,node.protocols.tcp.policy,node.protocols.tcp.ports,node.protocols.udp.policy,node.protocols.udp.ports,node.isActive,node.name,node.createdAt,node.updatedAt
UmVzb3VyY2U6MjU3Mg==,AWS,DNS,twindemo.int,True,ALLOW_ALL,[],ALLOW_ALL,[],True,AWS SSH,2021-01-20T15:54:53.046611+00:00,2022-05-06T21:14:45.766635+00:00
UmVzb3VyY2U6MjkxMw==,AWS,DNS,grafana.twindemo.int,True,ALLOW_ALL,[],ALLOW_ALL,[],True,AWS Grafana Admin,2021-02-09T02:41:48.605518+00:00,2021-10-05T02:08:13.938672+00:00
```

And here is the same output in **DF**:

```text
myhost % python3 ./tgcli.py -s OrangeElk -f DF resource list
                     node.id   node.remoteNetwork.name  ...                    node.createdAt                    node.updatedAt
0       UmVzb3VyY2U6MjU3Mg==                       AWS  ...  2021-01-20T15:54:53.046611+00:00  2022-05-06T21:14:45.766635+00:00
1       UmVzb3VyY2U6MjkxMw==                       AWS  ...  2021-02-09T02:41:48.605518+00:00  2021-10-05T02:08:13.938672+00:00
```

## Going Further

You can freely experiment with the various object types supported by the CLI. Remember to periodically pull the latest version of the CLI from its repository.

We will continue to add features to the CLI itself, feel free to make suggestions and report issues on the repository page itself!
