@devkong/cli-nx 0.0.67-alpha.24 → 0.0.67-alpha.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/generators/preset/files/python/requirements.txt +4 -1
- package/src/generators/preset/files/python-with-s3/src/frontend.py +6 -0
- package/src/generators/preset/files/python-with-s3/src/input_data.py +17 -0
- package/src/generators/preset/files/python-with-s3/src/main.py +54 -0
- package/src/generators/preset/files/python-with-s3/src/main_test.py +40 -0
- package/src/generators/preset/files/python-with-s3/src/output_data.py +21 -0
- package/src/generators/preset/files/python-with-s3/src/s3.py +27 -0
- package/src/generators/preset/generator.js +7 -5
- package/src/generators/preset/generator.js.map +1 -1
- package/src/generators/preset/schema.d.ts +1 -2
- package/src/generators/preset/schema.json +8 -3
- /package/src/generators/preset/files/{python-advanced → python-with-secret}/src/frontend.py +0 -0
- /package/src/generators/preset/files/{python-advanced → python-with-secret}/src/input_data.py +0 -0
- /package/src/generators/preset/files/{python-advanced → python-with-secret}/src/main.py +0 -0
- /package/src/generators/preset/files/{python-advanced → python-with-secret}/src/main_test.py +0 -0
- /package/src/generators/preset/files/{python-advanced → python-with-secret}/src/output_data.py +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from kong.sdk.kong_function_request import KongFunctionRequest
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ExecuteData(BaseModel):
|
|
6
|
+
key: str = Field(
|
|
7
|
+
examples=["test/example.json"],
|
|
8
|
+
description="Key (path) of the object to download from the S3 bucket",
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class InputData(BaseModel):
|
|
13
|
+
request: KongFunctionRequest
|
|
14
|
+
|
|
15
|
+
execute: ExecuteData = Field(
|
|
16
|
+
description="Parameters for the 'execute' operation",
|
|
17
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from datetime import timedelta
|
|
3
|
+
|
|
4
|
+
from frontend import frontend
|
|
5
|
+
from input_data import InputData
|
|
6
|
+
from kong.sdk.app import App
|
|
7
|
+
from kong.sdk.app_logger import app_logger
|
|
8
|
+
from kong.sdk.kong_function import KongFunction
|
|
9
|
+
from kong.sdk.kong_function_context import KongFunctionContext
|
|
10
|
+
from kong.sdk.s3 import S3Secret
|
|
11
|
+
from output_data import OutputData
|
|
12
|
+
from s3 import create_s3_client
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Main(KongFunction):
|
|
16
|
+
__logger = app_logger(__name__)
|
|
17
|
+
|
|
18
|
+
async def handle(self, data: InputData, context: KongFunctionContext) -> OutputData:
|
|
19
|
+
secret: S3Secret = context.secret.get("s3").data
|
|
20
|
+
client = await context.state.use(
|
|
21
|
+
key=f"{secret.endpoint}:{secret.port}:{secret.bucket}:{secret.access_key}",
|
|
22
|
+
create=lambda: create_s3_client(secret),
|
|
23
|
+
unused=(timedelta(minutes=5), lambda c: c.close()),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
response = await client.get_object(
|
|
27
|
+
Bucket=secret.bucket,
|
|
28
|
+
Key=data.execute.key,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
body = await response["Body"].read()
|
|
32
|
+
self.__logger.info(
|
|
33
|
+
"have response from S3",
|
|
34
|
+
lambda: {
|
|
35
|
+
"bucket": secret.bucket,
|
|
36
|
+
"key": data.execute.key,
|
|
37
|
+
"size": len(body),
|
|
38
|
+
},
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return OutputData(
|
|
42
|
+
key=data.execute.key,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
app = App(
|
|
47
|
+
InputData,
|
|
48
|
+
OutputData,
|
|
49
|
+
Main,
|
|
50
|
+
frontend,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
app.run(sys.argv)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from datetime import timedelta
|
|
2
|
+
from types import SimpleNamespace
|
|
3
|
+
|
|
4
|
+
from frontend import frontend
|
|
5
|
+
from input_data import ExecuteData, InputData
|
|
6
|
+
from kong.sdk.conftest import ExtensionFixture, extension_test_context
|
|
7
|
+
from kong.sdk.kong_function_request import KongFunctionRequest
|
|
8
|
+
from kong.sdk.kong_state_context import KongStateContext
|
|
9
|
+
from kong.sdk.s3 import S3Secret
|
|
10
|
+
from main import Main, client_cache_key
|
|
11
|
+
|
|
12
|
+
S3_SECRET = S3Secret(
|
|
13
|
+
access_key="access",
|
|
14
|
+
secret_key="secret",
|
|
15
|
+
bucket="my-bucket",
|
|
16
|
+
region="us-east-1",
|
|
17
|
+
endpoint=None,
|
|
18
|
+
port=None,
|
|
19
|
+
use_ssl=True,
|
|
20
|
+
path_style=False,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def test_should_download_object_from_s3(
|
|
25
|
+
create_extension: ExtensionFixture,
|
|
26
|
+
):
|
|
27
|
+
extension = create_extension(Main, InputData)
|
|
28
|
+
|
|
29
|
+
input_data = InputData(
|
|
30
|
+
request=KongFunctionRequest(operation="execute"),
|
|
31
|
+
execute=ExecuteData(key="test/example.json"),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
context = extension_test_context(
|
|
35
|
+
frontend,
|
|
36
|
+
secrets={"s3": S3_SECRET},
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
output = await extension.handle(input_data, context)
|
|
40
|
+
assert output.key == "test/example.json"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OutputData(BaseModel):
|
|
7
|
+
key: str = Field(
|
|
8
|
+
examples=["test/example.json"],
|
|
9
|
+
description="Key of the object that was downloaded",
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
size: int = Field(
|
|
13
|
+
examples=[42],
|
|
14
|
+
description="Size of the downloaded object, in bytes",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
content: Optional[str] = Field(
|
|
18
|
+
default=None,
|
|
19
|
+
examples=['{"hello": "world"}'],
|
|
20
|
+
description="UTF-8 decoded content of the downloaded object",
|
|
21
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from aiobotocore.session import get_session
|
|
2
|
+
from botocore.config import Config
|
|
3
|
+
from kong.sdk.s3 import S3Secret
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async def create_s3_client(secret: S3Secret):
|
|
7
|
+
# Standard AWS endpoints are derived by boto from the region; only S3-compatible
|
|
8
|
+
# stores (MinIO, Ceph, ...) need an explicit endpoint override.
|
|
9
|
+
endpoint_url = None
|
|
10
|
+
if secret.endpoint and "amazonaws.com" not in secret.endpoint:
|
|
11
|
+
scheme = "https" if secret.use_ssl else "http"
|
|
12
|
+
endpoint_url = (
|
|
13
|
+
f"{scheme}://{secret.endpoint}:{secret.port}"
|
|
14
|
+
if secret.port
|
|
15
|
+
else f"{scheme}://{secret.endpoint}"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
client_context = get_session().create_client(
|
|
19
|
+
"s3",
|
|
20
|
+
region_name=secret.region,
|
|
21
|
+
endpoint_url=endpoint_url,
|
|
22
|
+
use_ssl=secret.use_ssl,
|
|
23
|
+
aws_access_key_id=secret.access_key,
|
|
24
|
+
aws_secret_access_key=secret.secret_key,
|
|
25
|
+
config=(Config(s3={"addressing_style": "path"}) if secret.path_style else None),
|
|
26
|
+
)
|
|
27
|
+
return await client_context.__aenter__()
|
|
@@ -16,11 +16,13 @@ function presetGenerator(tree, options) {
|
|
|
16
16
|
options.os = process.platform;
|
|
17
17
|
options.variant = (_a = options.variant) !== null && _a !== void 0 ? _a : "basic";
|
|
18
18
|
(0, devkit_1.generateFiles)(tree, path.join(__dirname, `files/${options.platform}`), "", options);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
const pythonVariantDirs = {
|
|
20
|
+
"with-secret": "files/python-with-secret",
|
|
21
|
+
"with-s3": "files/python-with-s3",
|
|
22
|
+
};
|
|
23
|
+
const variantDir = pythonVariantDirs[options.variant];
|
|
24
|
+
if (options.platform === "python" && variantDir) {
|
|
25
|
+
(0, devkit_1.generateFiles)(tree, path.join(__dirname, variantDir), "", options);
|
|
24
26
|
}
|
|
25
27
|
yield (0, devkit_1.formatFiles)(tree);
|
|
26
28
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../src/generators/preset/generator.ts"],"names":[],"mappings":";;AAUA,
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../src/generators/preset/generator.ts"],"names":[],"mappings":";;AAUA,0CA+BC;;AAzCD,uCAMoB;AACpB,mDAA6B;AAG7B,SAAsB,eAAe,CAAC,IAAU,EAAE,OAA8B;;;QAC9E,MAAM,WAAW,GAAG,GAAG,CAAC;QACxB,MAAM,WAAW,GAAG,EAAE,CAAC;QACvB,IAAA,gCAAuB,EAAC,IAAI,EAAE,WAAW,EAAE;YACzC,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,aAAa;SAC3B,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC9B,OAAO,CAAC,OAAO,GAAG,MAAA,OAAO,CAAC,OAAO,mCAAI,OAAO,CAAC;QAC7C,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QAEpF,MAAM,iBAAiB,GAA2B;YAChD,aAAa,EAAE,0BAA0B;YACzC,SAAS,EAAE,sBAAsB;SAClC,CAAC;QACF,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACtD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,UAAU,EAAE,CAAC;YAChD,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;QAExB,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAA,0BAAiB,EAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YAC9D,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,YAAY;YAC1D,CAAC;QACH,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;CAAA;AAED,kBAAe,eAAe,CAAC"}
|
|
@@ -6,6 +6,5 @@ export interface PresetGeneratorSchema {
|
|
|
6
6
|
os?: string;
|
|
7
7
|
platform: "python" | "kotlin";
|
|
8
8
|
// Which starter template to scaffold. Only the python preset currently ships more
|
|
9
|
-
|
|
10
|
-
variant?: "basic" | "advanced";
|
|
9
|
+
variant?: "basic" | "with-secret" | "with-s3";
|
|
11
10
|
}
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"description": "Which starter template to scaffold",
|
|
28
28
|
"enum": [
|
|
29
29
|
"basic",
|
|
30
|
-
"
|
|
30
|
+
"with-secret",
|
|
31
|
+
"with-s3"
|
|
31
32
|
],
|
|
32
33
|
"default": "basic",
|
|
33
34
|
"x-prompt": {
|
|
@@ -39,8 +40,12 @@
|
|
|
39
40
|
"label": "basic - a single operation"
|
|
40
41
|
},
|
|
41
42
|
{
|
|
42
|
-
"value": "
|
|
43
|
-
"label": "
|
|
43
|
+
"value": "with-secret",
|
|
44
|
+
"label": "with-secret - multiple operations with a secret example"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"value": "with-s3",
|
|
48
|
+
"label": "with-s3 - download a file from S3 using an s3 secret"
|
|
44
49
|
}
|
|
45
50
|
]
|
|
46
51
|
}
|
|
File without changes
|
/package/src/generators/preset/files/{python-advanced → python-with-secret}/src/input_data.py
RENAMED
|
File without changes
|
|
File without changes
|
/package/src/generators/preset/files/{python-advanced → python-with-secret}/src/main_test.py
RENAMED
|
File without changes
|
/package/src/generators/preset/files/{python-advanced → python-with-secret}/src/output_data.py
RENAMED
|
File without changes
|