Skip to content

Commit 69ef527

Browse files
committed
Add simple python example to get devices
* Later, it will support getting SSH information Signed-off-by: Ryan Friedman <[email protected]>
1 parent e22fd6f commit 69ef527

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Python SSH Connection Config
2+
3+
This application uses `python` to create a SSH connection to a device, and then write an entry in your SSH config file.
4+
5+
## Usage
6+
7+
1. [Set up your Remote.it credentials](https://docs.remote.it/developer-tools/authentication#create-a-remote.it-credentials-file)
8+
1. Install requirements with pip
9+
* `python3 -m pip install -r requirements.txt`
10+
1. Run a query in python
11+
* `./run_query.py --help`
12+
* `./run_query.py`
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
configparser
2+
pyyaml
3+
requests-http-signature==v0.1.0
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
from base64 import b64decode
5+
import configparser
6+
import pathlib
7+
import requests
8+
from requests_http_signature import HTTPSignatureAuth
9+
import yaml
10+
11+
DEFAULT_SECTION = "default"
12+
13+
# TODO construct schemas using graphene
14+
QUERY_GET_ALL_DEVICES = "query { login { id email devices { items { id name state}}}}"
15+
16+
17+
def run_query(
18+
credentials: configparser.ConfigParser, *, query, section=DEFAULT_SECTION
19+
):
20+
# Modified from https://docs.remote.it/developer-tools/authentication#api-request-signing
21+
key_id = credentials[section].get("R3_ACCESS_KEY_ID")
22+
key_secret_id = credentials[section].get("R3_SECRET_ACCESS_KEY")
23+
24+
body = {"query": query}
25+
host = "api.remote.it"
26+
url_path = "/graphql/v1"
27+
content_type_header = "application/json"
28+
content_length_header = str(len(body))
29+
30+
headers = {
31+
"host": host,
32+
"path": url_path,
33+
"content-type": content_type_header,
34+
"content-length": content_length_header,
35+
}
36+
37+
# This should work with 0.7.1 but doesn't, likely due to remote.it using an outdated draft standard.
38+
# This seems to have changed behavior in 0.3.0.
39+
# response = requests.post(
40+
# "https://" + host + url_path,
41+
# json=body,
42+
# auth=HTTPSignatureAuth(
43+
# # todo import algorithms from requests_http_signature
44+
# signature_algorithm=algorithms.HMAC_SHA256,
45+
# key=b64decode(key_secret_id),
46+
# key_id=key_id,
47+
# covered_component_ids=[
48+
# "@request-target",
49+
# "host",
50+
# "@date",
51+
# "content-type",
52+
# "content-length"
53+
# ]
54+
# # headers=[
55+
# # "(request-target)",
56+
# # "host",
57+
# # "date",
58+
# # "content-type",
59+
# # "content-length",
60+
# # ],
61+
# ),
62+
# headers=headers,
63+
# )
64+
65+
response = requests.post(
66+
"https://" + host + url_path,
67+
json=body,
68+
auth=HTTPSignatureAuth(
69+
algorithm="hmac-sha256",
70+
key=b64decode(key_secret_id),
71+
key_id=key_id,
72+
headers=[
73+
"(request-target)",
74+
"host",
75+
"date",
76+
"content-type",
77+
"content-length",
78+
],
79+
),
80+
headers=headers,
81+
)
82+
83+
if response.status_code == 200:
84+
print(yaml.dump(response.json()))
85+
else:
86+
print(response.status_code)
87+
print(response.text)
88+
89+
90+
def read_ssh_config() -> configparser.ConfigParser:
91+
config_path = pathlib.Path.home() / ".remoteit" / "credentials"
92+
try:
93+
assert config_path.exists()
94+
except AssertionError as e:
95+
print(f"Not found: {config_path}")
96+
raise e
97+
cfg_parser = configparser.ConfigParser()
98+
cfg_parser.read(config_path)
99+
100+
return cfg_parser
101+
102+
103+
def validate_credentials(
104+
credentials: configparser.ConfigParser, *, section=DEFAULT_SECTION
105+
):
106+
sections = credentials.sections()
107+
# TODO support selecting a section other than default
108+
assert section in sections
109+
cred_section = credentials[section]
110+
assert "R3_ACCESS_KEY_ID" in cred_section
111+
assert "R3_SECRET_ACCESS_KEY" in cred_section
112+
113+
114+
def main():
115+
parser = argparse.ArgumentParser()
116+
parser.add_argument(
117+
"--section",
118+
type=str,
119+
required=False,
120+
help="Section of credentials to use for auth",
121+
default=DEFAULT_SECTION,
122+
)
123+
args = parser.parse_args()
124+
creds = read_ssh_config()
125+
validate_credentials(creds, section=args.section)
126+
run_query(creds, query=QUERY_GET_ALL_DEVICES, section=args.section)
127+
128+
129+
if __name__ == "__main__":
130+
main()

0 commit comments

Comments
 (0)