Skip to content
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

release 1.0.9 #25

Merged
merged 7 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 55 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

- [Prerequisites](https://github.com/Oreoxmt/tidbcloudy#prerequisites)
- [List all resources in your organization](https://github.com/Oreoxmt/tidbcloudy#list-all-resources-in-your-organization)
- [Create a project and manage your AWS CMEK](https://github.com/Oreoxmt/tidbcloudy#create-a-project-and-manage-your-aws-cmek) **New in 1.0.9**
- [Create a cluster](https://github.com/Oreoxmt/tidbcloudy#create-a-cluster)
- [Connect to TiDB](https://github.com/Oreoxmt/tidbcloudy#connect-to-tidb)
- [Modify a cluster](https://github.com/Oreoxmt/tidbcloudy#modify-a-cluster)
Expand All @@ -35,15 +36,15 @@ If you do not have a TiDB Cloud account yet, you can sign up [here](https://tidb
You can use this SDK to access [TiDB Cloud](https://tidbcloud.com) and manage your billings, projects, clusters, backups and restores:

- manage your **billings** of your organization (_get_)
- manage your TiDB Cloud **projects** (only _list_ is supported now)
- manage your TiDB Cloud **projects** (_list_, _create_) and manage the **AWS CMEK** of your projects (_get_, _create_)
- list all available cloud providers (AWS and GCP), regions, and specifications before creating or modifying a cluster
- manage your TiDB Serverless or TiDB Dedicated **clusters** (_create_, _modify_, _pause_, _resume_, _get_, _list_, _delete_)
- manage your **backups** of a cluster (_create_, _get_, _list_, _delete_)
- manage your **restores** of a project (_create_, _get_, _list_)

### Compatibility with TiDB Cloud API

`tidbcloudy` is compatible with TiDB Cloud API. **Endpoints added in [v1beta Release 20230228](https://docs.pingcap.com/tidbcloud/api/v1beta#section/API-Changelog/20230228), [v1beta Release 20230328](https://docs.pingcap.com/tidbcloud/api/v1beta#section/API-Changelog/20230328), and [v1beta Release 20230905](https://docs.pingcap.com/tidbcloud/api/v1beta#section/API-Changelog/20230905) are not supported for now**. The following table lists the compatibility between `tidbcloudy` and TiDB Cloud API.
`tidbcloudy` is compatible with TiDB Cloud API. **Endpoints added in [v1beta Release 20230228](https://docs.pingcap.com/tidbcloud/api/v1beta#section/API-Changelog/20230228) and [v1beta Release 20230905](https://docs.pingcap.com/tidbcloud/api/v1beta#section/API-Changelog/20230905) are not supported for now**. The following table lists the compatibility between `tidbcloudy` and TiDB Cloud API.

<table>
<thead>
Expand All @@ -70,6 +71,23 @@ You can use this SDK to access [TiDB Cloud](https://tidbcloud.com) and manage yo
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://github.com/Oreoxmt/tidbcloudy/releases/tag/v1.0.9" target="_blank" rel="noopener noreferrer">1.0.9</a></td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td><a href="https://github.com/Oreoxmt/tidbcloudy/releases/tag/v1.0.8" target="_blank" rel="noopener noreferrer">1.0.8</a></td>
<td>✅</td>
Expand Down Expand Up @@ -316,6 +334,8 @@ To get full code examples, see the [`examples`](https://github.com/Oreoxmt/tidbc

### List all resources in your organization

**This feature is available in `tidbcloudy` 1.0.9 or later.**

To get the full code example of listing all projects, clusters, backup tasks, and restore tasks in your organization, see [`0_list_resources.py`](https://github.com/Oreoxmt/tidbcloudy/tree/main/examples/0_list_resources.py).

```python
Expand All @@ -331,6 +351,9 @@ api = tidbcloudy.TiDBCloud(public_key=public_key, private_key=private_key)

for project in api.iter_projects():
print(project)
if project.aws_cmek_enabled:
for aws_cmek in project.iter_aws_cmek():
print(aws_cmek)
for cluster in project.iter_clusters():
print(cluster)
if cluster.cluster_type == ClusterType.DEDICATED:
Expand All @@ -340,6 +363,32 @@ for project in api.iter_projects():
print(restore)
```

### Create a project and manage your AWS CMEK

To create a project, run the [`8_manage_project.py`](https://github.com/Oreoxmt/tidbcloudy/tree/main/examples/8_manage_project.py).

```python
import os

import tidbcloudy

public_key = os.environ.get("PUBLIC_KEY")
private_key = os.environ.get("PRIVATE_KEY")
debug_mode = os.environ.get("TIDBCLOUDY_LOG")

api = tidbcloudy.TiDBCloud(public_key=public_key, private_key=private_key)
# Create a project with AWS CMEK enabled
project = api.create_project(name="0", aws_cmek_enabled=True, update_from_server=True)
print(project)

# Configure AWS CMEK for the project
project.create_aws_cmek([("your_aws_region_1", "your_aws_kms_arn_1"), ("your_aws_region_2", "your_aws_kms_arn_2")])

# List all AWS CMEKs of the project
for cmek in project.iter_aws_cmek():
print(cmek)
```

### Create a cluster

Before creating a cluster, you should list all available provider regions and cluster configuration specifications. For more details, run the [`1_list_provider_regions.py`](https://github.com/Oreoxmt/tidbcloudy/tree/main/examples/1_list_provider_regions.py).
Expand Down Expand Up @@ -524,6 +573,8 @@ for restore in project.iter_restores():

### Pause or resume your cluster

**This feature is available in `tidbcloudy` 1.0.0 or later.**

To pause or resume your cluster, run the [`6_pause_cluster.py`](https://github.com/Oreoxmt/tidbcloudy/tree/main/examples/6_pause_cluster.py).

```python
Expand Down Expand Up @@ -554,6 +605,8 @@ if cluster.status.cluster_status == ClusterStatus.RESUMING:

### Get monthly bills of your organization

**This feature is available in `tidbcloudy` 1.0.8 or later.**

To get the billing information of your organization, run the [`v1beta1_get_monthly_bill.py`](https://github.com/Oreoxmt/tidbcloudy/tree/main/examples/v1beta1_get_monthly_bill.py).

```python
Expand Down
12 changes: 11 additions & 1 deletion examples/0_list_resources.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import os

import tidbcloudy
from tidbcloudy.backup import Backup
from tidbcloudy.cluster import Cluster
from tidbcloudy.project import Project
from tidbcloudy.specification import ClusterType
from tidbcloudy.restore import Restore
from tidbcloudy.specification import ClusterType, ProjectAWSCMEK

public_key = os.environ.get("PUBLIC_KEY")
private_key = os.environ.get("PRIVATE_KEY")
Expand All @@ -14,12 +17,19 @@
for project in api.iter_projects():
assert isinstance(project, Project)
print(project)
if project.aws_cmek_enabled:
for aws_cmek in project.iter_aws_cmek():
assert isinstance(aws_cmek, ProjectAWSCMEK)
print(aws_cmek)
for cluster in project.iter_clusters():
assert isinstance(cluster, Cluster)
print(cluster)
if cluster.cluster_type == ClusterType.DEDICATED:
for backup in cluster.iter_backups():
assert isinstance(backup, Backup)
print(backup)
for restore in project.iter_restores():
assert isinstance(restore, Restore)
print(restore)

# get_project() does not fetch full information of a project from the server by default
Expand Down
2 changes: 1 addition & 1 deletion examples/2_1_create_serverless_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
project = api.get_project(project_id, update_from_server=True)

config = CreateClusterConfig()
config\
config \
.set_name("serverless-0") \
.set_cluster_type("DEVELOPER") \
.set_cloud_provider("AWS") \
Expand Down
2 changes: 1 addition & 1 deletion examples/2_2_create_dedicated_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
project = api.get_project(project_id, update_from_server=True)

config = CreateClusterConfig()
config\
config \
.set_name("dedicated-1") \
.set_cluster_type("DEDICATED") \
.set_cloud_provider("AWS") \
Expand Down
19 changes: 19 additions & 0 deletions examples/8_manage_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os

import tidbcloudy

public_key = os.environ.get("PUBLIC_KEY")
private_key = os.environ.get("PRIVATE_KEY")
debug_mode = os.environ.get("TIDBCLOUDY_LOG")

api = tidbcloudy.TiDBCloud(public_key=public_key, private_key=private_key)
# Create a project with AWS CMEK enabled
project = api.create_project(name="0", aws_cmek_enabled=True, update_from_server=True)
print(project)

# Configure AWS CMEK for the project
project.create_aws_cmek([("your_aws_region_1", "your_aws_kms_arn_1"), ("your_aws_region_2", "your_aws_kms_arn_2")])

# List all AWS CMEKs of the project
for cmek in project.iter_aws_cmek():
print(cmek)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "tidbcloudy"
version = "1.0.8"
version = "1.0.9"
description = "(Unofficial) Python SDK for TiDB Cloud"
readme = "README.md"
authors = ["Aolin <[email protected]>"]
Expand Down
82 changes: 76 additions & 6 deletions tidbcloudy/project.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
from typing import Union, Iterator
from typing import Iterator, List, Tuple, Union

from ._base import TiDBCloudyBase, TiDBCloudyContextualBase, TiDBCloudyField
from .cluster import Cluster
from .restore import Restore
from .specification import CreateClusterConfig, UpdateClusterConfig
from .util.timestamp import timestamp_to_string
from .specification import CreateClusterConfig, ProjectAWSCMEK, UpdateClusterConfig
from .util.page import Page
from .util.timestamp import timestamp_to_string


# noinspection PyShadowingBuiltins
class Project(TiDBCloudyBase, TiDBCloudyContextualBase):
__slots__ = ["_id", "_org_id", "_name", "_cluster_count", "_user_count", "_create_timestamp"]
__slots__ = ["_id", "_org_id", "_name", "_cluster_count", "_user_count", "_create_timestamp", "_aws_cmek_enabled"]
id: str = TiDBCloudyField(str)
org_id: str = TiDBCloudyField(str)
name: str = TiDBCloudyField(str)
cluster_count: int = TiDBCloudyField(int)
user_count: int = TiDBCloudyField(int)
create_timestamp: int = TiDBCloudyField(int, convert_from=int, convert_to=str)
aws_cmek_enabled: bool = TiDBCloudyField(bool)

def create_cluster(self, config: Union[CreateClusterConfig, dict]) -> Cluster:
"""
Expand Down Expand Up @@ -248,6 +249,75 @@ def iter_restores(self, page_size: int = 10) -> Iterator[Restore]:
yield restore
page += 1

def create_aws_cmek(self, config: List[Tuple[str, str]]) -> None:
"""
Configure the AWS Customer-Managed Encryption Keys (CMEK) for the project.
Args:
config: the configuration of the CMEK. The format is [(region, kms_arn), ...]

Examples:
.. code-block:: python
import tidbcloudy
api = tidbcloudy.TiDBCloud(public_key="your_public_key", private_key="your_private_key")
project = api.create_project(name="your_project_name", aws_cmek_enabled=True, update_from_server=True)
project.create_aws_cmek([(region, kms_arn), ...]
for cmek in project.iter_aws_cmek():
print(cmek)
"""
payload = {
"specs": []
}
for region, kms_arn in config:
payload["specs"].append({
"region": region,
"kms_arn": kms_arn
})
path = f"projects/{self.id}/aws-cmek"
self.context.call_post(path=path, json=payload)

def list_aws_cmek(self) -> Page[ProjectAWSCMEK]:
"""
List all AWS Customer-Managed Encryption Keys (CMEK) in the project.

Returns:
The page of the CMEK in the project.

Examples:
.. code-block:: python
import tidbcloudy
api = tidbcloudy.TiDBCloud(public_key="your_public_key", private_key="your_private_key")
project = api.get_project(project_id)
cmeks = project.list_aws_cmek()
for cmek in cmeks.items:
print(cmek)
"""
path = f"projects/{self.id}/aws-cmek"
resp = self.context.call_get(path=path)
total = len(resp["items"])
return Page(
[ProjectAWSCMEK.from_object(self.context, item) for item in resp["items"]],
1, total, total)

def iter_aws_cmek(self) -> Iterator[ProjectAWSCMEK]:
"""
This is not a TiDB Cloud API official endpoint.
Iterate all AWS Customer-Managed Encryption Keys (CMEK) in the project.

Returns:
The iterator of the CMEK in the project.

Examples:
.. code-block:: python
import tidbcloudy
api = tidbcloudy.TiDBCloud(public_key="your_public_key", private_key="your_private_key")
project = api.get_project(project_id)
for cmek in project.iter_aws_cmek():
print(cmek)
"""
cmeks = self.list_aws_cmek()
for cmek in cmeks.items:
yield cmek

def __repr__(self):
return "<Project id={} name={} create_at={}>".format(
self.id, self.name, timestamp_to_string(self.create_timestamp))
return "<Project id={} name={} aws_cmek_enabled={} create_at={}>".format(
self.id, self.name, self.aws_cmek_enabled, timestamp_to_string(self.create_timestamp))
10 changes: 10 additions & 0 deletions tidbcloudy/specification.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,16 @@ def __repr__(self):
self.status.value if self.status is not None else None)


class ProjectAWSCMEK(TiDBCloudyBase):
__slots__ = ["_region", "_kms_arn"]
region: str = None
kms_arn: str = None

def __repr__(self):
return "<region={}, kms_arn={}>".format(
self.region, self.kms_arn)


class BillingBase(TiDBCloudyBase):
__slots__ = ["_credits", "_discounts", "_runningTotal", "_totalCost"]
credits: str = TiDBCloudyField(str)
Expand Down
29 changes: 29 additions & 0 deletions tidbcloudy/tidbcloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,35 @@ class TiDBCloud:
def __init__(self, public_key: str, private_key: str):
self._context = Context(public_key, private_key)

def create_project(self, name: str, aws_cmek_enabled: bool = False, update_from_server: bool = False) -> Project:
"""
Create a project.
Args:
name: the project name.
aws_cmek_enabled: whether to enable AWS Customer-Managed Encryption Keys.
update_from_server: whether to update the project info after creating.

Returns:
If the update_from_server is False, return a Project object with only the context and project_id.
If the update_from_server is True, return a Project object with all the info.

Examples:
.. code-block:: python
import tidbcloudy
api = tidbcloudy.TiDBCloud(public_key="your_public_key", private_key="your_private_key")
project = api.create_project(name="your_project_name", aws_cmek_enabled=False, update_from_server=True)
print(project)
"""
config = {
"name": name,
"aws_cmek_enabled": aws_cmek_enabled
}
resp = self._context.call_post(path="projects", json=config)
project_id = resp["id"]
if update_from_server:
return self.get_project(project_id=project_id, update_from_server=True)
return Project(context=self._context, id=project_id)

def get_project(self, project_id: str, update_from_server: bool = False) -> Project:
"""
Get the project object by project_id.
Expand Down