Skip to content

Commit 3539b34

Browse files
authored
Move destination config into config file (#14)
* Move destination into config file * Update config and docs * Update tests * Bump 0.6.0
1 parent 72edc87 commit 3539b34

File tree

8 files changed

+204
-126
lines changed

8 files changed

+204
-126
lines changed

README.md

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,60 @@ pip install cloud2sql
2020

2121
## Usage
2222

23-
The sources for `cloud2sql` are configured via a configuration file. Create your own configuration by adjusting the [config template file](./config-template.yaml).
23+
The sources and destinations for `cloud2sql` are configured via a configuration file. Create your own configuration by adjusting the [config template file](./config-template.yaml).
2424
You can safely delete the sections that are not relevant to you (e.g. if you do not use AWS, you can delete the `aws` section).
2525
All sections refer to cloud providers and are enabled if a configuration section is provided.
2626

27-
After the sources are configured, you need to define the url to the database.
2827
The following databases are currently supported:
2928

3029
#### SQLite
3130

3231
```
33-
sqlite:///path/to/resoto.db
32+
destinations:
33+
sqlite:
34+
database: /path/to/database.db
3435
```
3536

3637
#### PostgreSQL
3738

3839
```
39-
postgresql://user:password@host:port/dbname[?key=value&key=value...]
40+
destinations:
41+
postgresql:
42+
host: 127.0.0.1
43+
port: 5432
44+
user: cloud2sql
45+
password: changeme
46+
database: cloud2sql
47+
args:
48+
key: value
4049
```
4150

4251
#### MySQL
4352

4453
```
45-
mysql://username:password@host/dbname[?key=value&key=value...]
54+
destinations:
55+
mysql:
56+
host: 127.0.0.1
57+
port: 3306
58+
user: cloud2sql
59+
password: changeme
60+
database: cloud2sql
61+
args:
62+
key: value
4663
```
4764

4865
#### MariaDB
4966

5067
```
51-
mariadb://username:password@host/dbname[?key=value&key=value...]
68+
destinations:
69+
mariadb:
70+
host: 127.0.0.1
71+
port: 3306
72+
user: cloud2sql
73+
password: changeme
74+
database: cloud2sql
75+
args:
76+
key: value
5277
```
5378

5479
#### My database is not listed here
@@ -62,7 +87,7 @@ We use a minimal configuration [example](./config-example.yaml) and export the d
6287
The example uses our AWS default credentials and the default kubernetes config.
6388

6489
```bash
65-
cloud2sql --config config-example.yaml --db "sqlite:///resoto.db"
90+
cloud2sql --config config-example.yaml
6691
```
6792

6893
## Local Development
@@ -73,4 +98,3 @@ Create a local development environment with the following command:
7398
make setup
7499
source venv/bin/activate
75100
```
76-

cloud2sql/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
__author__ = "Some Engineering Inc."
1212
__license__ = "Apache 2.0"
1313
__copyright__ = "Copyright © 2022 Some Engineering Inc."
14-
__version__ = "0.5.0"
14+
__version__ = "0.6.0"

cloud2sql/__main__.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from sqlalchemy.engine import Engine
88

99
from cloud2sql.analytics import PosthogEventSender, NoEventSender, AnalyticsEventSender
10-
from cloud2sql.collect_plugins import collect_from_plugins
10+
from cloud2sql.collect_plugins import collect_from_plugins, configure
11+
from cloud2sql.util import db_string_from_config
1112

1213
# Will fail in case snowflake is not installed - which is fine.
1314
try:
@@ -32,11 +33,6 @@ def parse_args() -> Namespace:
3233
default="progress",
3334
help="Output to show during the process. Default: progress",
3435
)
35-
parser.add_argument(
36-
"--db",
37-
help="The database url. See https://docs.sqlalchemy.org/en/20/core/engines.html.",
38-
required=True,
39-
)
4036
parser.add_argument(
4137
"--analytics-opt-out",
4238
default=False,
@@ -62,7 +58,8 @@ def main() -> None:
6258
try:
6359
setup_logger("resoto.cloud2sql", level=args.log_level, force=True)
6460
sender = NoEventSender() if args.analytics_opt_out else PosthogEventSender()
65-
engine = create_engine(args.db)
61+
config = configure(args.config)
62+
engine = create_engine(db_string_from_config(config))
6663
collect(engine, args, sender)
6764
except Exception as e:
6865
if args.debug: # raise exception and show complete tracelog

cloud2sql/collect_plugins.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,17 @@ def collectors(raw_config: Json, feedback: CoreFeedback) -> Dict[str, BaseCollec
5151

5252

5353
def configure(path_to_config: Optional[str]) -> Json:
54+
config = {}
5455
if path_to_config:
5556
with open(path_to_config) as f:
56-
return yaml.safe_load(f) # type: ignore
57-
return {}
57+
config = yaml.safe_load(f) # type: ignore
58+
59+
if "sources" not in config:
60+
raise ValueError("No sources configured")
61+
if "destinations" not in config:
62+
raise ValueError("No destinations configured")
63+
64+
return config
5865

5966

6067
def collect(
@@ -137,7 +144,8 @@ def collect_from_plugins(engine: Engine, args: Namespace, sender: AnalyticsEvent
137144
core_messages: Queue[Json] = mp_manager.Queue()
138145
feedback = CoreFeedback("cloud2sql", "collect", "collect", core_messages)
139146
raw_config = configure(args.config)
140-
all_collectors = collectors(raw_config, feedback)
147+
sources = raw_config["sources"]
148+
all_collectors = collectors(sources, feedback)
141149
analytics = {"total": len(all_collectors), "engine": engine.dialect.name} | {name: 1 for name in all_collectors}
142150
end = Event()
143151
with ThreadPoolExecutor(max_workers=4) as executor:

cloud2sql/util.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Union, List, Optional, Any
22

3-
from resotolib.types import JsonElement
3+
from resotolib.types import JsonElement, Json
44

55

66
def value_in_path(element: JsonElement, path_or_name: Union[List[str], str]) -> Optional[Any]:
@@ -16,3 +16,40 @@ def at_idx(current: JsonElement, idx: int) -> Optional[Any]:
1616
return at_idx(current[path[idx]], idx + 1)
1717

1818
return at_idx(element, 0)
19+
20+
21+
def db_string_from_config(config: Json) -> str:
22+
destinations = config.get("destinations", {})
23+
24+
if len(destinations) != 1:
25+
raise ValueError("Exactly one destination must be configured")
26+
27+
db_type = list(destinations.keys())[0]
28+
db_config = destinations[db_type]
29+
user = db_config.get("user")
30+
password = db_config.get("password")
31+
host = db_config.get("host")
32+
port = db_config.get("port")
33+
database = db_config.get("database")
34+
args = db_config.get("args", {})
35+
36+
db_uri = f"{db_type}://"
37+
38+
if user:
39+
db_uri += user
40+
if password:
41+
db_uri += f":{password}"
42+
db_uri += "@"
43+
44+
if host:
45+
db_uri += host
46+
if port:
47+
db_uri += f":{port}"
48+
49+
if database:
50+
db_uri += f"/{database}"
51+
52+
if len(args) > 0:
53+
db_uri += "?" + "&".join([f"{k}={v}" for k, v in args.items()])
54+
55+
return db_uri

config-example.yaml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
aws:
2-
# Take the aws default profile in ~/.aws/credentials and collect 2 regions
3-
region: ["us-east-1", "eu-central-1"]
1+
sources:
2+
aws:
3+
# Take the aws default profile in ~/.aws/credentials and collect 2 regions
4+
region: ["us-east-1", "eu-central-1"]
45

5-
k8s:
6-
# Use the default kubeconfig file and collect all contexts.
7-
config_files:
8-
- path: "~/.kube/config"
9-
all_contexts: true
6+
k8s:
7+
# Use the default kubeconfig file and collect all contexts.
8+
config_files:
9+
- path: "~/.kube/config"
10+
all_contexts: true
11+
destinations:
12+
sqlite:
13+
database: resoto.db

0 commit comments

Comments
 (0)