Compliance policy provisioning should be done in us-central region
Architecture policy should support 2 tiers of the database
Small disk size 20 GB
Big disk size 40 GB
Archtecture policy:
Small tier's VM should be db-g1-small
Big tier's VM should be db-n1-standard-1
Product team option to choose between Postgres and MySQL
Product team should specify the size in the XR with 2 enums (SMALL or BIG)
Platform team Patch the zone in which the database is created back into the XR/claim status field for monitoring requirements
Creating the XRD
Api Group: alpha-beta.imarunrk.com
XR name: XGCPdb
Claim name: GCPdb
API version: v1
size as input parameter
zone as response status attribute
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
#'<plural name>.<group>'
name: xgcpdbs.alpha-beta.imarunrk.com
spec:
# We will group the APIs under the alpha-beta group
group: alpha-beta.imarunrk.com
# Singular name and plural name of GCP DB.
names:
kind: XGCPdb
plural: xgcpdbs
# Providing the claim API name for the product team
claimNames:
kind: GCPdb
plural: gcpdbs
# We will start with version v1 for the first release.
versions:
- name: v1
# This is an actively served version
served: true
# We should be able to create composition for this version
referenceable: true
# OpenAPI schema
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
# Size will be a user input
parameters:
type: object
properties:
size:
type: string
required:
- size
required:
- parameters
status:
type: object
# Recourse zone - status patch parameter.
properties:
zone:
description: DB zone.
type: string
EOF
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
xgcpdbs.alpha-beta.imarunrk.com True True 21s
ESTABLISHED and OFFERED flags in the screenshot are True
This means that the XRD is created correctly
If these statuses are not True, use kubectl to describe the details of the XRD and look for an error
Providing implementation
Provide an API implementation (provide composition configuration)
Polymorphic behavior - will create 2 compositions one for Postgres and MySQL
The following are the steps to remember when we build the composition YAML:
Refer to the v1 XRD API version with the CompositeTypeRef configuration.
Define the CloudSQLInstance configuration under the resource base.
Hardcode the region to us-central1 to meet the compliance requirement.
The database tier and disk size will hold default values, but the patch configuration will overlay them using the FromCompositeFieldPath patch type.
Use the Map transformation to convert the SMALL tier size to the db-g1-small machine tier. Use the Map and Convert transformations to map the SMALL tier size to the 20 GB disk size.
Similar mapping will be done for the BIG configuration.
Patch the GceZone attribute from the MR status to the XR/claim for monitoring. We can achieve this using the ToCompositeFieldPath patch type.
Provide a mapping between the MR connection secret key to the XR/claim keys with the ConnectionDetails configuration.
Postgres Composition
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: postgres
labels:
# An optional label used for easy discovery
crossplane.io/xrd: xgcpdbs.alpha-beta.imarunrk.com
spec:
# Refer to an XRD API version
compositeTypeRef:
apiVersion: alpha-beta.imarunrk.com/v1
kind: XGCPdb
writeConnectionSecretsToNamespace: crossplane-system
resources:
# Provide configuration for Postgres resource
- name: cloudsqlinstance
base:
apiVersion: database.gcp.crossplane.io/v1beta1
kind: CloudSQLInstance
spec:
# reference to GCP credentials
providerConfigRef:
name: gcp-credentials-project-1
forProvider:
databaseVersion: POSTGRES_9_6
# Complience Policy
region: us-central1
settings:
# These are default values
# We will patch this to match architecture policy
tier: db-g1-small
dataDiskSizeGb: 20
patches:
# Patch tier in composition from XR/Claim
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.settings.tier
# Use map transform
# If the from-field value is BIG, then
# the mapped to-field value is db-n1-standard-1
transforms:
- type: map
map:
BIG: db-n1-standard-1
SMALL: db-g1-small
policy:
# return error if there is no field.
fromFieldPath: Required
# Patch disk size in composition from XR/Claim
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.settings.dataDiskSizeGb
# If the from-field value is BIG, then
# the mapped to-field value is '40;
# Apply the second transform to convert '40' to int
transforms:
- type: map
map:
BIG: "40"
SMALL: "20"
- type: convert
convert:
toType: int
policy:
# return error if there is no field.
fromFieldPath: Required
# Patch zone information back to the XR status
# No transformation or policy required
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.gceZone
toFieldPath: status.zone
# Propagating CloudSQLInstance connection secret to the XR
connectionDetails:
- name: hostname
fromConnectionSecretKey: hostname
EOF
MySQL Composition
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: mysql
labels:
# An optional label used for easy discovery
crossplane.io/xrd: xgcpdbs.alpha-beta.imarunrk.com
spec:
# Refer a XRD API version
compositeTypeRef:
apiVersion: alpha-beta.imarunrk.com/v1
kind: XGCPdb
writeConnectionSecretsToNamespace: crossplane-system
resources:
# Provide configuration for Postgres resource
- name: cloudsqlinstance
base:
apiVersion: database.gcp.crossplane.io/v1beta1
kind: CloudSQLInstance
spec:
# reference to GCP credentials
providerConfigRef:
name: gcp-credentials-project-1
forProvider:
databaseVersion: MYSQL_5_7
# Complience Policy
region: us-central1
settings:
# These are default values
# We will patch this to match architecture policy
tier: db-g1-small
dataDiskSizeGb: 20
patches:
# Patch tier in composition from XR/Claim
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.settings.tier
# Use map transform
# If the from-field value is BIG, then
# the mapped to-field value is db-n1-standard-1
transforms:
- type: map
map:
BIG: db-n1-standard-1
SMALL: db-g1-small
policy:
# return error if there is no field.
fromFieldPath: Required
# Patch disk size in composition from XR/Claim
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.settings.dataDiskSizeGb
# If the from-field value is BIG, then
# the mapped to-field value is '40;
# Apply the second transform to convert '40' to int
transforms:
- type: map
map:
BIG: "40"
SMALL: "20"
- type: convert
convert:
toType: int
policy:
# return error if there is no field.
fromFieldPath: Required
# Patch zone information back to the XR status
# No transformation or policy required
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.gceZone
toFieldPath: status.zone
# Propagating CloudSQLInstance connection secret to the XR
connectionDetails:
- name: hostname
fromConnectionSecretKey: hostname
EOF
kubectl get compositions
NAME XR-KIND XR-APIVERSION AGE
mysql XGCPdb alpha-beta.imarunrk.com/v1 5s
postgres XGCPdb alpha-beta.imarunrk.com/v1 84s
Provisioning the resources with a claim
With help of compositions we can provision GCP database with an XR or a claim
Claims are namespace resources, will provision it in alpha namespace
MySQL claim
cat <<EOF | kubectl apply -f -
apiVersion: alpha-beta.imarunrk.com/v1
kind: GCPdb
metadata:
# Claims in alpha namespace
namespace: alpha
name: mysql-db
spec:
# refer to the mysql composition
compositionRef:
name: mysql
# save connection details as secret - db-conn
writeConnectionSecretToRef:
name: db-conn2
parameters:
size: SMALL
EOF
kubectl get cloudsqlinstance
NAME READY SYNCED STATE VERSION AGE
mysql-db-drfl6-f6z78 True True RUNNABLE MYSQL_5_7 18m
kubectl get gcpdb -n alpha
NAME SYNCED READY CONNECTION-SECRET AGE
mysql-db True True db-conn2 18m