Skip to content

Commit 28ca94c

Browse files
committed
[sdlf-*] restore legacy seedfarmer deployspec
1 parent 0c815a6 commit 28ca94c

File tree

6 files changed

+510
-61
lines changed

6 files changed

+510
-61
lines changed

sdlf-dataset/deployspec.yaml

Lines changed: 127 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,142 @@
1-
publishGenericEnvVariables: True
1+
publishGenericEnvVariables: true
22
deploy:
33
phases:
44
install:
55
commands:
6-
- npm install -g aws-cdk
76
- |-
8-
pip install --upgrade pip setuptools
9-
pip install poetry
10-
poetry config virtualenvs.create false --local
11-
poetry install -v
7+
# force Python3.12
8+
rm -Rf ~/.venv/
9+
pyenv global 3.12
10+
python3 -m venv ~/.venv
11+
. ~/.venv/bin/activate
12+
pip install --upgrade pip setuptools
13+
pip install aws-codeseeder~=1.1.0 seed-farmer==5.0.0
14+
- |-
15+
CFN_ENDPOINT="https://cloudformation.$AWS_REGION.amazonaws.com"
16+
ARTIFACTS_BUCKET=$(aws cloudformation --endpoint-url "$CFN_ENDPOINT" describe-stacks --query "Stacks[?StackName=='aws-codeseeder-$SEEDFARMER_PROJECT_NAME'][].Outputs[?OutputKey=='Bucket'].OutputValue" --output text)
17+
18+
deps=(
19+
"https://raw.githubusercontent.com/aws/serverless-application-model/develop/bin/sam-translate.py"
20+
"https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip"
21+
"https://raw.githubusercontent.com/awslabs/aws-serverless-data-lake-framework/main/sdlf-cicd/template-generic-cfn-module.yaml"
22+
)
23+
for u in "${deps[@]}"; do
24+
aws s3api get-object --bucket "$ARTIFACTS_BUCKET" --key "${u##*/}" "${u##*/}" || {
25+
curl -L -O "$u"
26+
aws s3api put-object --bucket "$ARTIFACTS_BUCKET" --key "${u##*/}" --body "${u##*/}"
27+
}
28+
done
29+
- |-
30+
pip uninstall -y aws-sam-cli && unzip -q aws-sam-cli-linux-x86_64.zip -d sam-installation
31+
./sam-installation/install && sam --version
32+
pip install "cfn-lint<1" cloudformation-cli poetry
33+
npm install -g aws-cdk@2.159.1
34+
poetry config virtualenvs.create false --local
1235
build:
1336
commands:
1437
- |-
15-
cdk deploy --all --require-approval never --progress events --app "python src/app.py" --outputs-file ./cdk-exports.json
16-
- seedfarmer metadata convert -f cdk-exports.json || true
38+
# deployment-type possible values: cfn-module, cdk-construct
39+
# cfn-module creates a CloudFormation Registry module out of template.yaml
40+
# cdk-construct publishes a pip library out of template.py on CodeArtifact
41+
echo "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE"
42+
- |-
43+
if [ "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE" = "cfn-module" ]; then
44+
# SEEDFARMER_PARAMETER_LIBRARY_MODULE can be used to pass the module name. If not, the module name is inferred from SEEDFARMER_MODULE_NAME
45+
# by removing everything up to the first hyphen, then anything that isn't a letter/number, and lower-casing everything.
46+
sf_module_name_without_prefix="${SEEDFARMER_MODULE_NAME#*-}"
47+
sf_module_name_alnum="${sf_module_name_without_prefix//[^[:alnum:]]/}"
48+
MODULE="${sf_module_name_alnum,,}"
49+
50+
: "${SEEDFARMER_PARAMETER_LIBRARY_ORG:=awslabs}" "${SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK:=sdlf}" "${SEEDFARMER_PARAMETER_LIBRARY_MODULE:=$MODULE}"
51+
cd src || exit
52+
sam package --template-file ./dataset.yaml --s3-bucket "$ARTIFACTS_BUCKET" --s3-prefix sdlf --output-template-file template.yaml
53+
python3 ../sam-translate.py --template-file=template.yaml --output-template=translated-template.json
54+
55+
SSM_ENDPOINT="https://ssm.$AWS_REGION.amazonaws.com"
56+
TEMPLATE_BASE_FILE_PATH="modules/$SEEDFARMER_PARAMETER_LIBRARY_ORG/$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK/$SEEDFARMER_PARAMETER_LIBRARY_MODULE"
57+
aws s3api put-object --bucket "$ARTIFACTS_BUCKET" --key "$TEMPLATE_BASE_FILE_PATH/translated-template.json" --body translated-template.json
58+
TEMPLATE_URL="https://$ARTIFACTS_BUCKET.s3.$AWS_REGION.amazonaws.com/$TEMPLATE_BASE_FILE_PATH/translated-template.json"
59+
aws cloudformation --endpoint-url "$CFN_ENDPOINT" validate-template --template-url "$TEMPLATE_URL"
60+
61+
mkdir module
62+
cd module || exit
63+
cfn init --artifact-type MODULE --type-name "$SEEDFARMER_PARAMETER_LIBRARY_ORG::$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK::$SEEDFARMER_PARAMETER_LIBRARY_MODULE::MODULE" && rm fragments/sample.json
64+
cp -i -a ../translated-template.json fragments/
65+
cfn generate
66+
zip -q -r "../$SEEDFARMER_PARAMETER_LIBRARY_MODULE.zip" .rpdk-config fragments/ schema.json
67+
68+
NEW_MODULE="$(sha256sum "../$SEEDFARMER_PARAMETER_LIBRARY_MODULE.zip" | cut -c1-12)"
69+
aws s3api put-object --bucket "$ARTIFACTS_BUCKET" --key "$TEMPLATE_BASE_FILE_PATH-$NEW_MODULE.zip" --body "../$SEEDFARMER_PARAMETER_LIBRARY_MODULE.zip"
70+
71+
if CURRENT_MODULE=$(aws ssm --endpoint-url "$SSM_ENDPOINT" get-parameter --name "/SDLF/CFN/$SEEDFARMER_PARAMETER_LIBRARY_ORG-$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK-$SEEDFARMER_PARAMETER_LIBRARY_MODULE-MODULE" --query "Parameter.Value" --output text); then
72+
echo "Current module hash: $CURRENT_MODULE / New module hash: $NEW_MODULE"
73+
if [ "$NEW_MODULE" == "$CURRENT_MODULE" ]; then
74+
echo "No change since last build, exiting module creation."
75+
exit 0
76+
fi
77+
fi
78+
79+
STACK_NAME="sdlf-cfn-module-$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK-$SEEDFARMER_PARAMETER_LIBRARY_MODULE"
80+
aws cloudformation --endpoint-url "$CFN_ENDPOINT" deploy \
81+
--stack-name "$STACK_NAME" \
82+
--template-file ../../template-generic-cfn-module.yaml \
83+
--parameter-overrides \
84+
pArtifactsBucket="$ARTIFACTS_BUCKET" \
85+
pLibraryOrg="$SEEDFARMER_PARAMETER_LIBRARY_ORG" \
86+
pLibraryFramework="$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK" \
87+
pLibraryModule="$SEEDFARMER_PARAMETER_LIBRARY_MODULE" \
88+
pModuleGitRef="$NEW_MODULE" \
89+
--tags Framework=sdlf || exit 1
90+
echo "done"
91+
cd .. && rm -Rf module
92+
fi
93+
- |-
94+
if [ "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE" = "cdk-construct" ]; then
95+
CA_ENDPOINT="https://codeartifact.$AWS_REGION.amazonaws.com"
96+
CA_REPOSITORY_ENDPOINT=$(aws codeartifact --endpoint-url "$CA_ENDPOINT" get-repository-endpoint --domain "$SEEDFARMER_PARAMETER_CODEARTIFACT_DOMAIN" --domain-owner "$AWS_ACCOUNT_ID" --repository "$SEEDFARMER_PARAMETER_CODEARTIFACT_REPOSITORY" --format pypi --query repositoryEndpoint --output text)
97+
CA_TOKEN=$(aws codeartifact --endpoint-url "$CA_ENDPOINT" get-authorization-token --domain "$SEEDFARMER_PARAMETER_CODEARTIFACT_DOMAIN" --domain-owner "$AWS_ACCOUNT_ID" --query authorizationToken --output text)
98+
poetry source add private "https://aws:${CA_TOKEN}@${CA_REPOSITORY_ENDPOINT#https://}simple/"
99+
poetry install -v
100+
poetry config repositories.private "$CA_REPOSITORY_ENDPOINT"
101+
poetry config http-basic.private aws "$CA_TOKEN"
102+
poetry publish --skip-existing --build -r private || exit 1
103+
fi
104+
post_build:
105+
commands:
106+
- echo "Deploy successful"
17107
destroy:
18108
phases:
19109
install:
20110
commands:
21-
- npm install -g aws-cdk
22111
- |-
23-
pip install --upgrade pip setuptools
24-
pip install poetry
25-
poetry config virtualenvs.create false --local
26-
poetry install -v
112+
pip install --upgrade pip setuptools
113+
pip install poetry
27114
build:
28115
commands:
29-
- cdk destroy --force --all --app "python src/app.py"
116+
- |-
117+
echo "DESTROY! $SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE"
118+
- |-
119+
if [ "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE" = "cfn-module" ]; then
120+
CFN_ENDPOINT="https://cloudformation.$AWS_REGION.amazonaws.com"
121+
sf_module_name_without_prefix="${SEEDFARMER_MODULE_NAME#*-}"
122+
sf_module_name_alnum="${sf_module_name_without_prefix//[^[:alnum:]]/}"
123+
MODULE="${sf_module_name_alnum,,}"
124+
: "${SEEDFARMER_PARAMETER_LIBRARY_ORG:=awslabs}" "${SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK:=sdlf}" "${SEEDFARMER_PARAMETER_LIBRARY_MODULE:=$MODULE}"
125+
STACK_NAME="sdlf-cfn-module-$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK-$SEEDFARMER_PARAMETER_LIBRARY_MODULE"
126+
aws cloudformation --endpoint-url "$CFN_ENDPOINT" delete-stack --stack-name "$STACK_NAME" || exit 1
127+
fi
128+
- |-
129+
if [ "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE" = "cdk-construct" ]; then
130+
CA_ENDPOINT="https://codeartifact.$AWS_REGION.amazonaws.com"
131+
package_version_poetry=$(poetry version --short)
132+
package_prerelease_id=$(echo "$package_version_poetry" | cut -d'-' -f2 | cut -d'.' -f1)
133+
pypi_prerelease_id=$(test "$package_prerelease_id" = "rc" && echo "rc" || echo "${package_prerelease_id:0:1}")
134+
pypi_package_version="$(echo "$package_version_poetry" | cut -d'-' -f1)$pypi_prerelease_id$(echo "$package_version_poetry" | cut -d'-' -f2 | cut -d'.' -f2)"
135+
aws codeartifact --endpoint-url "$CA_ENDPOINT" delete-package-versions \
136+
--domain "$SEEDFARMER_PARAMETER_CODEARTIFACT_DOMAIN" --domain-owner "$AWS_ACCOUNT_ID" \
137+
--repository "$SEEDFARMER_PARAMETER_CODEARTIFACT_REPOSITORY" --format pypi --package "$(poetry version | cut -d' ' -f1)" --versions "$pypi_package_version"
138+
fi
139+
post_build:
140+
commands:
141+
- echo "Destroy successful"
142+
build_type: BUILD_GENERAL1_SMALL

sdlf-foundations/deployspec.yaml

Lines changed: 127 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,142 @@
1-
publishGenericEnvVariables: True
1+
publishGenericEnvVariables: true
22
deploy:
33
phases:
44
install:
55
commands:
6-
- npm install -g aws-cdk
76
- |-
8-
pip install --upgrade pip setuptools
9-
pip install poetry
10-
poetry config virtualenvs.create false --local
11-
poetry install -v
7+
# force Python3.12
8+
rm -Rf ~/.venv/
9+
pyenv global 3.12
10+
python3 -m venv ~/.venv
11+
. ~/.venv/bin/activate
12+
pip install --upgrade pip setuptools
13+
pip install aws-codeseeder~=1.1.0 seed-farmer==5.0.0
14+
- |-
15+
CFN_ENDPOINT="https://cloudformation.$AWS_REGION.amazonaws.com"
16+
ARTIFACTS_BUCKET=$(aws cloudformation --endpoint-url "$CFN_ENDPOINT" describe-stacks --query "Stacks[?StackName=='aws-codeseeder-$SEEDFARMER_PROJECT_NAME'][].Outputs[?OutputKey=='Bucket'].OutputValue" --output text)
17+
18+
deps=(
19+
"https://raw.githubusercontent.com/aws/serverless-application-model/develop/bin/sam-translate.py"
20+
"https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip"
21+
"https://raw.githubusercontent.com/awslabs/aws-serverless-data-lake-framework/main/sdlf-cicd/template-generic-cfn-module.yaml"
22+
)
23+
for u in "${deps[@]}"; do
24+
aws s3api get-object --bucket "$ARTIFACTS_BUCKET" --key "${u##*/}" "${u##*/}" || {
25+
curl -L -O "$u"
26+
aws s3api put-object --bucket "$ARTIFACTS_BUCKET" --key "${u##*/}" --body "${u##*/}"
27+
}
28+
done
29+
- |-
30+
pip uninstall -y aws-sam-cli && unzip -q aws-sam-cli-linux-x86_64.zip -d sam-installation
31+
./sam-installation/install && sam --version
32+
pip install "cfn-lint<1" cloudformation-cli poetry
33+
npm install -g aws-cdk@2.159.1
34+
poetry config virtualenvs.create false --local
1235
build:
1336
commands:
1437
- |-
15-
env | grep "SEEDFARMER"
16-
cdk deploy --all --require-approval never --progress events --app "python src/app.py" --outputs-file ./cdk-exports.json
17-
- seedfarmer metadata convert -f cdk-exports.json || true
38+
# deployment-type possible values: cfn-module, cdk-construct
39+
# cfn-module creates a CloudFormation Registry module out of template.yaml
40+
# cdk-construct publishes a pip library out of template.py on CodeArtifact
41+
echo "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE"
42+
- |-
43+
if [ "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE" = "cfn-module" ]; then
44+
# SEEDFARMER_PARAMETER_LIBRARY_MODULE can be used to pass the module name. If not, the module name is inferred from SEEDFARMER_MODULE_NAME
45+
# by removing everything up to the first hyphen, then anything that isn't a letter/number, and lower-casing everything.
46+
sf_module_name_without_prefix="${SEEDFARMER_MODULE_NAME#*-}"
47+
sf_module_name_alnum="${sf_module_name_without_prefix//[^[:alnum:]]/}"
48+
MODULE="${sf_module_name_alnum,,}"
49+
50+
: "${SEEDFARMER_PARAMETER_LIBRARY_ORG:=awslabs}" "${SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK:=sdlf}" "${SEEDFARMER_PARAMETER_LIBRARY_MODULE:=$MODULE}"
51+
cd src || exit
52+
sam package --template-file ./foundations.yaml --s3-bucket "$ARTIFACTS_BUCKET" --s3-prefix sdlf --output-template-file template.yaml
53+
python3 ../sam-translate.py --template-file=template.yaml --output-template=translated-template.json
54+
55+
SSM_ENDPOINT="https://ssm.$AWS_REGION.amazonaws.com"
56+
TEMPLATE_BASE_FILE_PATH="modules/$SEEDFARMER_PARAMETER_LIBRARY_ORG/$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK/$SEEDFARMER_PARAMETER_LIBRARY_MODULE"
57+
aws s3api put-object --bucket "$ARTIFACTS_BUCKET" --key "$TEMPLATE_BASE_FILE_PATH/translated-template.json" --body translated-template.json
58+
TEMPLATE_URL="https://$ARTIFACTS_BUCKET.s3.$AWS_REGION.amazonaws.com/$TEMPLATE_BASE_FILE_PATH/translated-template.json"
59+
aws cloudformation --endpoint-url "$CFN_ENDPOINT" validate-template --template-url "$TEMPLATE_URL"
60+
61+
mkdir module
62+
cd module || exit
63+
cfn init --artifact-type MODULE --type-name "$SEEDFARMER_PARAMETER_LIBRARY_ORG::$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK::$SEEDFARMER_PARAMETER_LIBRARY_MODULE::MODULE" && rm fragments/sample.json
64+
cp -i -a ../translated-template.json fragments/
65+
cfn generate
66+
zip -q -r "../$SEEDFARMER_PARAMETER_LIBRARY_MODULE.zip" .rpdk-config fragments/ schema.json
67+
68+
NEW_MODULE="$(sha256sum "../$SEEDFARMER_PARAMETER_LIBRARY_MODULE.zip" | cut -c1-12)"
69+
aws s3api put-object --bucket "$ARTIFACTS_BUCKET" --key "$TEMPLATE_BASE_FILE_PATH-$NEW_MODULE.zip" --body "../$SEEDFARMER_PARAMETER_LIBRARY_MODULE.zip"
70+
71+
if CURRENT_MODULE=$(aws ssm --endpoint-url "$SSM_ENDPOINT" get-parameter --name "/SDLF/CFN/$SEEDFARMER_PARAMETER_LIBRARY_ORG-$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK-$SEEDFARMER_PARAMETER_LIBRARY_MODULE-MODULE" --query "Parameter.Value" --output text); then
72+
echo "Current module hash: $CURRENT_MODULE / New module hash: $NEW_MODULE"
73+
if [ "$NEW_MODULE" == "$CURRENT_MODULE" ]; then
74+
echo "No change since last build, exiting module creation."
75+
exit 0
76+
fi
77+
fi
78+
79+
STACK_NAME="sdlf-cfn-module-$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK-$SEEDFARMER_PARAMETER_LIBRARY_MODULE"
80+
aws cloudformation --endpoint-url "$CFN_ENDPOINT" deploy \
81+
--stack-name "$STACK_NAME" \
82+
--template-file ../../template-generic-cfn-module.yaml \
83+
--parameter-overrides \
84+
pArtifactsBucket="$ARTIFACTS_BUCKET" \
85+
pLibraryOrg="$SEEDFARMER_PARAMETER_LIBRARY_ORG" \
86+
pLibraryFramework="$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK" \
87+
pLibraryModule="$SEEDFARMER_PARAMETER_LIBRARY_MODULE" \
88+
pModuleGitRef="$NEW_MODULE" \
89+
--tags Framework=sdlf || exit 1
90+
echo "done"
91+
cd .. && rm -Rf module
92+
fi
93+
- |-
94+
if [ "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE" = "cdk-construct" ]; then
95+
CA_ENDPOINT="https://codeartifact.$AWS_REGION.amazonaws.com"
96+
CA_REPOSITORY_ENDPOINT=$(aws codeartifact --endpoint-url "$CA_ENDPOINT" get-repository-endpoint --domain "$SEEDFARMER_PARAMETER_CODEARTIFACT_DOMAIN" --domain-owner "$AWS_ACCOUNT_ID" --repository "$SEEDFARMER_PARAMETER_CODEARTIFACT_REPOSITORY" --format pypi --query repositoryEndpoint --output text)
97+
CA_TOKEN=$(aws codeartifact --endpoint-url "$CA_ENDPOINT" get-authorization-token --domain "$SEEDFARMER_PARAMETER_CODEARTIFACT_DOMAIN" --domain-owner "$AWS_ACCOUNT_ID" --query authorizationToken --output text)
98+
poetry source add private "https://aws:${CA_TOKEN}@${CA_REPOSITORY_ENDPOINT#https://}simple/"
99+
poetry install -v
100+
poetry config repositories.private "$CA_REPOSITORY_ENDPOINT"
101+
poetry config http-basic.private aws "$CA_TOKEN"
102+
poetry publish --skip-existing --build -r private || exit 1
103+
fi
104+
post_build:
105+
commands:
106+
- echo "Deploy successful"
18107
destroy:
19108
phases:
20109
install:
21110
commands:
22-
- npm install -g aws-cdk
23111
- |-
24-
pip install --upgrade pip setuptools
25-
pip install poetry
26-
poetry config virtualenvs.create false --local
27-
poetry install -v
112+
pip install --upgrade pip setuptools
113+
pip install poetry
28114
build:
29115
commands:
30-
- cdk destroy --force --all --app "python src/app.py"
116+
- |-
117+
echo "DESTROY! $SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE"
118+
- |-
119+
if [ "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE" = "cfn-module" ]; then
120+
CFN_ENDPOINT="https://cloudformation.$AWS_REGION.amazonaws.com"
121+
sf_module_name_without_prefix="${SEEDFARMER_MODULE_NAME#*-}"
122+
sf_module_name_alnum="${sf_module_name_without_prefix//[^[:alnum:]]/}"
123+
MODULE="${sf_module_name_alnum,,}"
124+
: "${SEEDFARMER_PARAMETER_LIBRARY_ORG:=awslabs}" "${SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK:=sdlf}" "${SEEDFARMER_PARAMETER_LIBRARY_MODULE:=$MODULE}"
125+
STACK_NAME="sdlf-cfn-module-$SEEDFARMER_PARAMETER_LIBRARY_FRAMEWORK-$SEEDFARMER_PARAMETER_LIBRARY_MODULE"
126+
aws cloudformation --endpoint-url "$CFN_ENDPOINT" delete-stack --stack-name "$STACK_NAME" || exit 1
127+
fi
128+
- |-
129+
if [ "$SEEDFARMER_PARAMETER_DEPLOYMENT_TYPE" = "cdk-construct" ]; then
130+
CA_ENDPOINT="https://codeartifact.$AWS_REGION.amazonaws.com"
131+
package_version_poetry=$(poetry version --short)
132+
package_prerelease_id=$(echo "$package_version_poetry" | cut -d'-' -f2 | cut -d'.' -f1)
133+
pypi_prerelease_id=$(test "$package_prerelease_id" = "rc" && echo "rc" || echo "${package_prerelease_id:0:1}")
134+
pypi_package_version="$(echo "$package_version_poetry" | cut -d'-' -f1)$pypi_prerelease_id$(echo "$package_version_poetry" | cut -d'-' -f2 | cut -d'.' -f2)"
135+
aws codeartifact --endpoint-url "$CA_ENDPOINT" delete-package-versions \
136+
--domain "$SEEDFARMER_PARAMETER_CODEARTIFACT_DOMAIN" --domain-owner "$AWS_ACCOUNT_ID" \
137+
--repository "$SEEDFARMER_PARAMETER_CODEARTIFACT_REPOSITORY" --format pypi --package "$(poetry version | cut -d' ' -f1)" --versions "$pypi_package_version"
138+
fi
139+
post_build:
140+
commands:
141+
- echo "Destroy successful"
142+
build_type: BUILD_GENERAL1_SMALL

0 commit comments

Comments
 (0)