├── Chapter03 ├── Hand-on-examples │ ├── CloudSQLInstance-MR │ │ └── SQL.yaml │ ├── GCP-Provider-Setup │ │ ├── GCP-API-Permissions.md │ │ ├── GCP-Provider.yaml │ │ ├── Helm-install.md │ │ ├── Provider-Config.yaml │ │ └── Service-account-creation.md │ └── Install-Crossplane │ │ └── Crossplane-install.md └── Samples │ ├── CR │ └── cr.yaml │ ├── CRD │ └── crd.yaml │ └── MR │ └── mr.yaml ├── Chapter04 ├── Hand-on-examples │ └── Build-an-XR │ │ ├── Claim-MySQL.yaml │ │ ├── Claim-postgres.yaml │ │ ├── MySQL.yaml │ │ ├── Postgres.yaml │ │ └── xrd.yaml └── Samples │ ├── Claim │ └── claim.yaml │ ├── Composition_ │ └── composition.yaml │ ├── Pre-provisioned-resources │ └── vpc.yaml │ ├── XR │ └── XR.yaml │ └── XRD │ └── xrd.yaml ├── Chapter05 ├── Hand-on-examples │ ├── Composition-Revision │ │ ├── Claim-Automatic.yaml │ │ ├── Claim-Manual.yaml │ │ ├── Composition-V1.yaml │ │ ├── Composition-V2.yaml │ │ └── xrd.yaml │ ├── Nested-Multi-Resource-XR │ │ ├── Claim-Application.yaml │ │ ├── Composition-Application.yaml │ │ ├── Composition-k8s.yaml │ │ ├── xrd-Application.yaml │ │ └── xrd-k8s.yaml │ ├── XRD-Contract-Change-Breaking │ │ ├── Claim-migrate.yaml │ │ ├── Claim.yaml │ │ ├── Composition-V1.yaml │ │ ├── Composition-V2.yaml │ │ ├── xrd-v1.yaml │ │ └── xrd-v2.yaml │ └── XRD-Contract-Change-Non-Breaking │ │ ├── Claim-v1-validate.yaml │ │ ├── Claim-v1.yaml │ │ ├── Claim-v2.yaml │ │ ├── Composition-V1.yaml │ │ ├── Composition-V2.yaml │ │ ├── xrd-v1.yaml │ │ └── xrd-v2.yaml └── Samples │ └── XRD-Versions │ ├── xrd-invalid-version-test.yaml │ └── xrd-multiple-version.yaml ├── Chapter06 └── Hand-on-examples │ ├── aws-setup │ ├── AWS-Provider.yaml │ ├── AWS-cli-install.md │ ├── AWS-kubernetes-credential.md │ ├── Provider-Config.yaml │ └── rds.yaml │ ├── different-xr-reference │ ├── claim-bucket.yaml │ ├── claim-iam.yaml │ ├── composition-IAM.yaml │ ├── composition-bucket.yaml │ ├── xrd-IAM.yaml │ └── xrd-bucket.yaml │ ├── helm-provider │ ├── GKE.yaml │ ├── Helm-Provider.yaml │ ├── Helm-test-deploy-upgrade.yaml │ ├── Helm-test-deploy.yaml │ └── Provider-Config.yaml │ ├── monitoring │ ├── GCP-Provider.yaml │ ├── SQL.yaml │ ├── alert.yaml │ ├── grafana.json │ ├── install-prometheus.md │ └── monitor.yaml │ ├── same-nested-xr-reference │ ├── claim-bucket.yaml │ ├── composition-IAM.yaml │ ├── composition-bucket.yaml │ ├── xrd-IAM.yaml │ └── xrd-bucket.yaml │ └── secret-propagation │ ├── claim-bucket.yaml │ ├── composition-IAM.yaml │ ├── composition-bucket.yaml │ ├── xrd-IAM.yaml │ └── xrd-bucket.yaml ├── Chapter07 ├── Hand-on-examples │ ├── configuration │ │ ├── Bucket │ │ │ ├── composition-bucket.yaml │ │ │ └── xrd-bucket.yaml │ │ ├── IAM │ │ │ ├── composition-IAM.yaml │ │ │ └── xrd-IAM.yaml │ │ └── crossplane.yaml │ └── test-configuration │ │ ├── bucketwithcredential │ │ ├── bucket-failure │ │ │ ├── 00-assert.yaml │ │ │ └── 00-install.yaml │ │ └── bucket-success │ │ │ ├── 00-assert.yaml │ │ │ └── 00-install.yaml │ │ ├── init │ │ └── provider-config.yaml │ │ └── kuttl-test.yaml └── Samples │ └── configuration.yaml ├── Chapter09 └── Hand-on-examples │ ├── KubeVela │ └── application.yaml │ ├── helm │ └── hello-world │ │ ├── Chart.yaml │ │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── hpa.yaml │ │ ├── ingress.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── tests │ │ │ └── test-connection.yaml │ │ └── values.yaml │ └── kustomize │ ├── example1 │ ├── deployment.yaml │ └── kustomization.yaml │ └── example2 │ ├── composition.yaml │ └── kustomization.yaml ├── Chapter10 └── Hands-on-example │ ├── Step-1-ProviderSetup │ └── Platform-OPS │ │ ├── Additional-Steps.md │ │ ├── GCP │ │ ├── GCP-Provider.yaml │ │ └── product-a │ │ │ ├── Provider-Config.yaml │ │ │ └── namespace.yaml │ │ ├── Gitlab │ │ ├── product-a │ │ │ └── provider-config.yaml │ │ └── provider-gitlab.yaml │ │ ├── Helm │ │ └── Helm-Provider.yaml │ │ └── k8s │ │ └── k8s-Provider.yaml │ ├── Step-2-CreateProductTeamsKubernetesCluster │ ├── Application-OPS │ │ └── cluster.yaml │ └── Platform-OPS │ │ ├── cluster-composition.yaml │ │ └── cluster-xrd.yaml │ ├── Step-3-GitProjectOnboarding │ ├── Additional-Steps.md │ ├── Application-OPS │ │ └── gitproject-claim.yaml │ └── Platform-OPS │ │ ├── gitproject-xrd.yaml │ │ └── gitprojects-composition.yaml │ └── Step-4-WebApplication │ ├── Application-OPS │ └── Claim-Application.yaml │ └── Platform-OPS │ ├── Application │ ├── web-application-composition-dev.yaml │ └── web-application-xrd.yaml │ └── DB │ ├── db-composition-MySQL.yaml │ └── db-xrd.yaml ├── LICENSE └── README.md /Chapter03/Hand-on-examples/CloudSQLInstance-MR/SQL.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: database.gcp.crossplane.io/v1beta1 2 | kind: CloudSQLInstance 3 | metadata: 4 | name: db-gcp-test 5 | spec: 6 | providerConfigRef: 7 | name: gcp-credentials-project-1 8 | writeConnectionSecretToRef: 9 | namespace: crossplane-system 10 | name: db-conn 11 | forProvider: 12 | databaseVersion: POSTGRES_9_6 13 | region: us-central 14 | settings: 15 | tier: db-g1-small 16 | dataDiskSizeGb: 20 -------------------------------------------------------------------------------- /Chapter03/Hand-on-examples/GCP-Provider-Setup/GCP-API-Permissions.md: -------------------------------------------------------------------------------- 1 | # Enable Kubernetes APIs 2 | 3 | gcloud services enable container.googleapis.com 4 | 5 | # Enable CloudSQL APIs 6 | 7 | gcloud services enable sqladmin.googleapis.com 8 | 9 | # Enable cloud compute APIs 10 | 11 | gcloud services enable compute.googleapis.com 12 | 13 | # Enable network APIs 14 | 15 | gcloud services enable servicenetworking.googleapis.com -------------------------------------------------------------------------------- /Chapter03/Hand-on-examples/GCP-Provider-Setup/GCP-Provider.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: provider-gcp 5 | spec: 6 | package: crossplane/provider-gcp:v0.18.0 -------------------------------------------------------------------------------- /Chapter03/Hand-on-examples/GCP-Provider-Setup/Helm-install.md: -------------------------------------------------------------------------------- 1 | # Install helm in mac 2 | 3 | brew install helm 4 | 5 | # Install helm in windows 6 | 7 | choco install kubernetes-helm -------------------------------------------------------------------------------- /Chapter03/Hand-on-examples/GCP-Provider-Setup/Provider-Config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: gcp.crossplane.io/v1beta1 2 | kind: ProviderConfig 3 | metadata: 4 | name: gcp-credentials-project-1 5 | spec: 6 | projectID: crossplane-339717 7 | credentials: 8 | source: Secret 9 | secretRef: 10 | namespace: crossplane-system 11 | name: gcp-account 12 | key: service-account -------------------------------------------------------------------------------- /Chapter03/Hand-on-examples/GCP-Provider-Setup/Service-account-creation.md: -------------------------------------------------------------------------------- 1 | # Get project ID 2 | gcloud projects list --format='value(project_id)' 3 | 4 | # Create service account 5 | gcloud iam service-accounts create crossplane-service-account --display-name "crossplane service account" --project=crossplane-330620 6 | 7 | # Get the name of the service account 8 | gcloud iam service-accounts list --filter="email ~ ^crossplane-service-account" --format='value(email)' 9 | 10 | # Add required IAM role to the service account 11 | gcloud projects add-iam-policy-binding crossplane-330620 --member "serviceAccount:crossplane-service-account@crossplane-330620.iam.gserviceaccount.com" --role="roles/iam.serviceAccountUser" 12 | 13 | gcloud projects add-iam-policy-binding crossplane-330620 --member "serviceAccount:crossplane-service-account@crossplane-330620.iam.gserviceaccount.com" --role="roles/cloudsql.admin" 14 | 15 | gcloud projects add-iam-policy-binding crossplane-330620 --member "serviceAccount:crossplane-service-account@crossplane-330620.iam.gserviceaccount.com" --role="roles/container.admin" 16 | 17 | gcloud projects add-iam-policy-binding crossplane-330620 --member "serviceAccount:crossplane-service-account@crossplane-330620.iam.gserviceaccount.com" --role="roles/redis.admin" 18 | 19 | gcloud projects add-iam-policy-binding crossplane-330620 --member "serviceAccount:crossplane-service-account@crossplane-330620.iam.gserviceaccount.com" --role="roles/compute.networkAdmin" 20 | 21 | gcloud projects add-iam-policy-binding crossplane-330620 --member "serviceAccount:crossplane-service-account@crossplane-330620.iam.gserviceaccount.com" --role="roles/storage.admin" 22 | 23 | # Extract the file and convert it into a base64 string 24 | 25 | gcloud iam service-accounts keys create crossplane-service-account.json --iam-account crossplane-service-account@crossplane-330620.iam.gserviceaccount.com 26 | 27 | base64 crossplane-service-account.json | tr -d "\n" 28 | -------------------------------------------------------------------------------- /Chapter03/Hand-on-examples/Install-Crossplane/Crossplane-install.md: -------------------------------------------------------------------------------- 1 | # Step 1: Create target namespace 2 | 3 | kubectl create namespace crossplane-system 4 | 5 | # Step 2: Add crossplane stable repo to helm and update 6 | 7 | helm repo add crossplane-stable https://charts.crossplane.io/stable 8 | helm repo update 9 | 10 | # Step 3: Install Crossplane 11 | 12 | helm install crossplane --namespace crossplane-system crossplane-stable/crossplane 13 | -------------------------------------------------------------------------------- /Chapter03/Samples/CR/cr.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "book.imarunrk.com/v1" 2 | kind: "CloudDB" 3 | metadata: 4 | name: "aws_RDS" 5 | spec: 6 | type: "sql" 7 | cloud : "aws" -------------------------------------------------------------------------------- /Chapter03/Samples/CRD/crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "apiextensions.k8s.io/v1beta1" 2 | kind: "CustomResourceDefinition" 3 | metadata: 4 | name: "clouddbs.book.imarunrk.com" 5 | spec: 6 | group: "book.imarunrk.com" 7 | version: "v1" 8 | scope: "Namespaced" 9 | names: 10 | plural: "clouddbs" 11 | singular: "clouddb" 12 | kind: "CloudDB" 13 | validation: 14 | openAPIV3Schema: 15 | required: ["spec"] 16 | properties: 17 | spec: 18 | required: ["type","cloud"] 19 | properties: 20 | type: 21 | type: "string" 22 | minimum: 1 23 | cloud: 24 | type: "string" 25 | minimum: 1 26 | -------------------------------------------------------------------------------- /Chapter03/Samples/MR/mr.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: database.gcp.crossplane.io/v1beta1 2 | kind: CloudSQLInstance 3 | metadata: 4 | name: my-GCP-DB 5 | spec: 6 | forProvider: 7 | databaseVersion: POSTGRES_9_6 8 | region: asia-south2 9 | settings: 10 | tier: db-n1-standard-1 11 | dataDiskSizeGb: 10 12 | writeConnectionSecretToRef: 13 | namespace: DB 14 | name: my-GCP-DB-credentials -------------------------------------------------------------------------------- /Chapter04/Hand-on-examples/Build-an-XR/Claim-MySQL.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: alpha-beta.imarunrk.com/v1 2 | kind: GCPdb 3 | metadata: 4 | # Claims in alpha namespace 5 | namespace: alpha 6 | name: mysql-db 7 | spec: 8 | # refer to the mysql composition 9 | compositionRef: 10 | name: mysql 11 | # save connection details as secret - db-conn 12 | writeConnectionSecretToRef: 13 | name: db-conn2 14 | parameters: 15 | size: SMALL 16 | -------------------------------------------------------------------------------- /Chapter04/Hand-on-examples/Build-an-XR/Claim-postgres.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: alpha-beta.imarunrk.com/v1 2 | kind: GCPdb 3 | metadata: 4 | # Claims in alpha namespace 5 | namespace: alpha 6 | name: postgres-db 7 | spec: 8 | # refer to the postgres composition 9 | compositionRef: 10 | name: postgres 11 | # save connection details as secret - db-conn 12 | writeConnectionSecretToRef: 13 | name: db-conn 14 | parameters: 15 | size: SMALL -------------------------------------------------------------------------------- /Chapter04/Hand-on-examples/Build-an-XR/MySQL.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: mysql 5 | labels: 6 | # An optional label used for easy discovery 7 | crossplane.io/xrd: xgcpdbs.alpha-beta.imarunrk.com 8 | spec: 9 | # Refer a XRD API version 10 | compositeTypeRef: 11 | apiVersion: alpha-beta.imarunrk.com/v1 12 | kind: XGCPdb 13 | writeConnectionSecretsToNamespace: crossplane-system 14 | resources: 15 | # Provide configuration for Postgres resource 16 | - name: cloudsqlinstance 17 | base: 18 | apiVersion: database.gcp.crossplane.io/v1beta1 19 | kind: CloudSQLInstance 20 | spec: 21 | # reference to GCP credentials 22 | providerConfigRef: 23 | name: gcp-credentials-project-1 24 | forProvider: 25 | databaseVersion: MYSQL_5_7 26 | # Complience Policy 27 | region: us-central1 28 | settings: 29 | # These are default values 30 | # We will patch this to match architecture policy 31 | tier: db-g1-small 32 | dataDiskSizeGb: 20 33 | patches: 34 | # Patch tier in composition from XR/Claim 35 | - type: FromCompositeFieldPath 36 | fromFieldPath: spec.parameters.size 37 | toFieldPath: spec.forProvider.settings.tier 38 | # Use map transform 39 | # If the from-field value is BIG, then 40 | # the mapped to-field value is db-n1-standard-1 41 | transforms: 42 | - type: map 43 | map: 44 | BIG: db-n1-standard-1 45 | SMALL: db-g1-small 46 | policy: 47 | # return error if there is no field. 48 | fromFieldPath: Required 49 | # Patch disk size in composition from XR/Claim 50 | - type: FromCompositeFieldPath 51 | fromFieldPath: spec.parameters.size 52 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 53 | # If the from-field value is BIG, then 54 | # the mapped to-field value is '40; 55 | # Apply the second transform to convert '40' to int 56 | transforms: 57 | - type: map 58 | map: 59 | BIG: "40" 60 | SMALL: "20" 61 | - type: convert 62 | convert: 63 | toType: int 64 | policy: 65 | # return error if there is no field. 66 | fromFieldPath: Required 67 | # Patch zone information back to the XR status 68 | # No transformation or policy required 69 | - type: ToCompositeFieldPath 70 | fromFieldPath: status.atProvider.gceZone 71 | toFieldPath: status.zone 72 | # Propagating CloudSQLInstance connection secret to the XR 73 | connectionDetails: 74 | - name: hostname 75 | fromConnectionSecretKey: hostname 76 | -------------------------------------------------------------------------------- /Chapter04/Hand-on-examples/Build-an-XR/Postgres.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: postgres 5 | labels: 6 | # An optional label used for easy discovery 7 | crossplane.io/xrd: xgcpdbs.alpha-beta.imarunrk.com 8 | spec: 9 | # Refer to an XRD API version 10 | compositeTypeRef: 11 | apiVersion: alpha-beta.imarunrk.com/v1 12 | kind: XGCPdb 13 | writeConnectionSecretsToNamespace: crossplane-system 14 | resources: 15 | # Provide configuration for Postgres resource 16 | - name: cloudsqlinstance 17 | base: 18 | apiVersion: database.gcp.crossplane.io/v1beta1 19 | kind: CloudSQLInstance 20 | spec: 21 | # reference to GCP credentials 22 | providerConfigRef: 23 | name: gcp-credentials-project-1 24 | forProvider: 25 | databaseVersion: POSTGRES_9_6 26 | # Complience Policy 27 | region: us-central1 28 | settings: 29 | # These are default values 30 | # We will patch this to match architecture policy 31 | tier: db-g1-small 32 | dataDiskSizeGb: 20 33 | patches: 34 | # Patch tier in composition from XR/Claim 35 | - type: FromCompositeFieldPath 36 | fromFieldPath: spec.parameters.size 37 | toFieldPath: spec.forProvider.settings.tier 38 | # Use map transform 39 | # If the from-field value is BIG, then 40 | # the mapped to-field value is db-n1-standard-1 41 | transforms: 42 | - type: map 43 | map: 44 | BIG: db-n1-standard-1 45 | SMALL: db-g1-small 46 | policy: 47 | # return error if there is no field. 48 | fromFieldPath: Required 49 | # Patch disk size in composition from XR/Claim 50 | - type: FromCompositeFieldPath 51 | fromFieldPath: spec.parameters.size 52 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 53 | # If the from-field value is BIG, then 54 | # the mapped to-field value is '40; 55 | # Apply the second transform to convert '40' to int 56 | transforms: 57 | - type: map 58 | map: 59 | BIG: "40" 60 | SMALL: "20" 61 | - type: convert 62 | convert: 63 | toType: int 64 | policy: 65 | # return error if there is no field. 66 | fromFieldPath: Required 67 | # Patch zone information back to the XR status 68 | # No transformation or policy required 69 | - type: ToCompositeFieldPath 70 | fromFieldPath: status.atProvider.gceZone 71 | toFieldPath: status.zone 72 | # Propagating CloudSQLInstance connection secret to the XR 73 | connectionDetails: 74 | - name: hostname 75 | fromConnectionSecretKey: hostname -------------------------------------------------------------------------------- /Chapter04/Hand-on-examples/Build-an-XR/xrd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | #'.' 5 | name: xgcpdbs.alpha-beta.imarunrk.com 6 | spec: 7 | # We will group the APIs under the alpha-beta group 8 | group: alpha-beta.imarunrk.com 9 | # Singular name and plural name of GCP DB. 10 | names: 11 | kind: XGCPdb 12 | plural: xgcpdbs 13 | # Providing the claim API name for the product team 14 | claimNames: 15 | kind: GCPdb 16 | plural: gcpdbs 17 | # We will start with version v1 for the first release. 18 | versions: 19 | - name: v1 20 | # This is an actively served version 21 | served: true 22 | # We should be able to create composition for this version 23 | referenceable: true 24 | # OpenAPI schema 25 | schema: 26 | openAPIV3Schema: 27 | type: object 28 | properties: 29 | spec: 30 | type: object 31 | properties: 32 | # Size will be a user input 33 | parameters: 34 | type: object 35 | properties: 36 | size: 37 | type: string 38 | required: 39 | - size 40 | required: 41 | - parameters 42 | status: 43 | type: object 44 | # Recourse zone - status patch parameter. 45 | properties: 46 | zone: 47 | description: DB zone. 48 | type: string 49 | -------------------------------------------------------------------------------- /Chapter04/Samples/Claim/claim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: book.imarunrk.com/v1 2 | # Kind name matches the singular claim name in the XRD 3 | kind: Clouddb 4 | metadata: 5 | name: cloud-db 6 | spec: 7 | # Parameters to be mapped and patched in the composition 8 | parameters: 9 | storageSize: 20 10 | # Name of the composition to be used 11 | compositionRef: 12 | name: xclouddb-composition 13 | writeConnectionSecretToRef: 14 | namespace: crossplane-system 15 | name: db-conn -------------------------------------------------------------------------------- /Chapter04/Samples/Composition_/composition.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: xclouddb-composition 5 | spec: 6 | # Link Composition to a specific XR and version 7 | compositeTypeRef: 8 | apiVersion: xclouddb.book.imarunrk.com/v1 9 | kind: Xclouddb 10 | # Connection secrets namespace 11 | writeConnectionSecretsToNamespace: crossplane-system 12 | # List of composed MRs or XRs. 13 | resources: 14 | - name: clouddbInstance 15 | # Resource base template 16 | base: 17 | apiVersion: database.gcp.crossplane.io/v1beta1 18 | kind: CloudSQLInstance 19 | spec: 20 | forProvider: 21 | databaseVersion: POSTGRES_9_6 22 | region: us-central 23 | settings: 24 | tier: db-g1-small 25 | dataDiskSizeGb: 20 26 | # Resource patches 27 | patches: 28 | - type: FromCompositeFieldPath 29 | fromFieldPath: spec.parameters.storageSize 30 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 31 | # Resource secrets 32 | connectionDetails: 33 | - name: hostname 34 | fromConnectionSecretKey: hostname -------------------------------------------------------------------------------- /Chapter04/Samples/Pre-provisioned-resources/vpc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: compute.gcp.crossplane.io/v1beta1 2 | kind: Network 3 | metadata: 4 | name: default-vpc-crossplane-ref 5 | # Label to refer the VPC using label selector 6 | labels: 7 | team: alpha-beta 8 | annotations: 9 | # Annotation to provide existing resource named 10 | crossplane.io/external-name: default 11 | spec: 12 | providerConfigRef: 13 | name: gcp-credentials-project-1 14 | # Provide the required parameters same as external resource. 15 | forProvider: 16 | autoCreateSubnetworks: true 17 | -------------------------------------------------------------------------------- /Chapter04/Samples/XR/XR.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: book.imarunrk.com/v1 2 | kind: XClouddb 3 | metadata: 4 | name: cloud-db 5 | spec: 6 | parameters: 7 | storageSize: 20 8 | compositionRef: 9 | name: xclouddb-composition 10 | writeConnectionSecretToRef: 11 | namespace: crossplane-system 12 | name: db-conn -------------------------------------------------------------------------------- /Chapter04/Samples/XRD/xrd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | #'.' 5 | name: xclouddbs.book.imarunrk.com 6 | spec: 7 | # API group 8 | group: book.imarunrk.com 9 | # Singular name and plural name. 10 | names: 11 | kind: xclouddb 12 | plural: xclouddbs 13 | # Optional parameter to create namespace proxy claim API 14 | claimNames: 15 | kind: Clouddb 16 | plural: Clouddbs 17 | # Start from alpha to beta to production to deprecated. 18 | versions: 19 | - name: v1 20 | # Is the specific version actively served 21 | served: true 22 | # Can the version be referenced from an API implementation 23 | referenceable: true 24 | # OpenAPI schema 25 | schema: 26 | openAPIV3Schema: 27 | type: object 28 | properties: 29 | spec: 30 | type: object 31 | properties: 32 | parameters: 33 | type: object 34 | properties: 35 | storageSize: 36 | type: integer 37 | required: 38 | - storageSize 39 | required: 40 | - parameters -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Composition-Revision/Claim-Automatic.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: composition-revision.imarunrk.com/v1 2 | kind: MySql 3 | metadata: 4 | namespace: alpha 5 | name: mysql-db 6 | spec: 7 | compositionRef: 8 | name: gcp-mysql 9 | parameters: 10 | size: 30 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Composition-Revision/Claim-Manual.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: composition-revision.imarunrk.com/v1 2 | kind: MySql 3 | metadata: 4 | namespace: alpha 5 | name: mysql-db-manual 6 | spec: 7 | compositionUpdatePolicy: Manual 8 | compositionRef: 9 | name: gcp-mysql 10 | parameters: 11 | size: 10 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Composition-Revision/Composition-V1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gcp-mysql 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: composition-revision.imarunrk.com/v1 8 | kind: XMySql 9 | resources: 10 | - name: cloudsqlinstance 11 | base: 12 | apiVersion: database.gcp.crossplane.io/v1beta1 13 | kind: CloudSQLInstance 14 | spec: 15 | providerConfigRef: 16 | name: gcp-credentials-project-1 17 | forProvider: 18 | region: us-central1 19 | databaseVersion: MYSQL_5_7 20 | settings: 21 | tier: db-g1-small 22 | dataDiskSizeGb: 40 23 | patches: 24 | - type: FromCompositeFieldPath 25 | fromFieldPath: spec.parameters.size 26 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 27 | -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Composition-Revision/Composition-V2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gcp-mysql 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: composition-revision.imarunrk.com/v1 8 | kind: XMySql 9 | resources: 10 | - name: cloudsqlinstance 11 | base: 12 | apiVersion: database.gcp.crossplane.io/v1beta1 13 | kind: CloudSQLInstance 14 | spec: 15 | providerConfigRef: 16 | name: gcp-credentials-project-1 17 | forProvider: 18 | region: us-central1 19 | databaseVersion: MYSQL_5_7 20 | settings: 21 | tier: db-g1-small 22 | dataDiskSizeGb: 40 23 | patches: 24 | - type: FromCompositeFieldPath 25 | fromFieldPath: spec.parameters.size 26 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 27 | transforms: 28 | - type: math 29 | math: 30 | multiply: 4 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Composition-Revision/xrd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xmysqls.composition-revision.imarunrk.com 5 | spec: 6 | group: composition-revision.imarunrk.com 7 | names: 8 | kind: XMySql 9 | plural: xmysqls 10 | claimNames: 11 | kind: MySql 12 | plural: mysqls 13 | versions: 14 | - name: v1 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | size: 28 | type: integer 29 | required: 30 | - size 31 | required: 32 | - parameters -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Nested-Multi-Resource-XR/Claim-Application.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nested-xr.imarunrk.com/v1 2 | kind: Application 3 | metadata: 4 | name: my-application 5 | namespace: alpha 6 | spec: 7 | parameters: 8 | region: us-central1 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Nested-Multi-Resource-XR/Composition-Application.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gcp-application 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: nested-xr.imarunrk.com/v1 8 | kind: XApplication 9 | resources: 10 | - name: cluster 11 | base: 12 | apiVersion: nested-xr.imarunrk.com/v1 13 | kind: XGCPCluster 14 | spec: 15 | parameters: 16 | region: us-central1-b 17 | autopilot: true 18 | patches: 19 | - type: FromCompositeFieldPath 20 | fromFieldPath: spec.parameters.region 21 | toFieldPath: spec.parameters.region 22 | - name: cloudsqlinstance 23 | base: 24 | apiVersion: database.gcp.crossplane.io/v1beta1 25 | kind: CloudSQLInstance 26 | spec: 27 | providerConfigRef: 28 | name: gcp-credentials-project-1 29 | forProvider: 30 | databaseVersion: MYSQL_5_7 31 | region: us-central1 32 | settings: 33 | tier: db-g1-small 34 | patches: 35 | - type: FromCompositeFieldPath 36 | fromFieldPath: spec.parameters.region 37 | toFieldPath: spec.forProvider.region 38 | -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Nested-Multi-Resource-XR/Composition-k8s.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gcp-kubernetes 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: nested-xr.imarunrk.com/v1 8 | kind: XGCPCluster 9 | resources: 10 | - name: cluster 11 | base: 12 | apiVersion: container.gcp.crossplane.io/v1beta2 13 | kind: Cluster 14 | spec: 15 | providerConfigRef: 16 | name: gcp-credentials-project-1 17 | forProvider: 18 | location: us-central1 19 | autopilot: 20 | enabled: true 21 | patches: 22 | - type: FromCompositeFieldPath 23 | fromFieldPath: spec.parameters.autopilot 24 | toFieldPath: spec.forProvider.autopilot.enabled 25 | - type: PatchSet 26 | patchSetName: region 27 | - name: bucket 28 | base: 29 | apiVersion: storage.gcp.crossplane.io/v1alpha3 30 | kind: Bucket 31 | spec: 32 | providerConfigRef: 33 | name: gcp-credentials-project-1 34 | forProvider: 35 | location: us-central1 36 | patches: 37 | - type: PatchSet 38 | patchSetName: region 39 | patchSets: 40 | - name: region 41 | patches: 42 | - type: FromCompositeFieldPath 43 | fromFieldPath: spec.parameters.region 44 | toFieldPath: spec.forProvider.region 45 | -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Nested-Multi-Resource-XR/xrd-Application.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xapplications.nested-xr.imarunrk.com 5 | spec: 6 | group: nested-xr.imarunrk.com 7 | names: 8 | kind: XApplication 9 | plural: xapplications 10 | claimNames: 11 | kind: Application 12 | plural: applications 13 | versions: 14 | - name: v1 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | region: 28 | type: string 29 | required: 30 | - region 31 | required: 32 | - parameters -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/Nested-Multi-Resource-XR/xrd-k8s.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xgcpclusters.nested-xr.imarunrk.com 5 | spec: 6 | group: nested-xr.imarunrk.com 7 | names: 8 | kind: XGCPCluster 9 | plural: xgcpclusters 10 | versions: 11 | - name: v1 12 | served: true 13 | referenceable: true 14 | schema: 15 | openAPIV3Schema: 16 | type: object 17 | properties: 18 | spec: 19 | type: object 20 | properties: 21 | parameters: 22 | type: object 23 | properties: 24 | autopilot: 25 | type: boolean 26 | region: 27 | type: string 28 | required: 29 | - region 30 | required: 31 | - parameters -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Breaking/Claim-migrate.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: xrd-breaking.imarunrk.com/v2 2 | kind: MySql 3 | metadata: 4 | namespace: alpha 5 | name: my-db 6 | labels: 7 | claim.name: my-db 8 | spec: 9 | compositionRef: 10 | name: gcp-mysql 11 | parameters: 12 | size: 20 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Breaking/Claim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: xrd-breaking.imarunrk.com/v1 2 | kind: MySql 3 | metadata: 4 | namespace: alpha 5 | name: my-db 6 | labels: 7 | claim.name: my-db 8 | spec: 9 | compositionRef: 10 | name: gcp-mysql 11 | parameters: 12 | size: 10 13 | vm: db-n1-standard-2 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Breaking/Composition-V1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gcp-mysql 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: xrd-breaking.imarunrk.com/v1 8 | kind: XMySql 9 | resources: 10 | - name: cloudsqlinstance 11 | base: 12 | apiVersion: database.gcp.crossplane.io/v1beta1 13 | kind: CloudSQLInstance 14 | metadata: 15 | annotations: 16 | crossplane.io/external-name: default 17 | spec: 18 | deletionPolicy: Orphan 19 | providerConfigRef: 20 | name: gcp-credentials-project-1 21 | forProvider: 22 | region: us-central1 23 | databaseVersion: MYSQL_5_7 24 | settings: 25 | tier: db-g1-small 26 | dataDiskSizeGb: 40 27 | patches: 28 | - type: FromCompositeFieldPath 29 | fromFieldPath: spec.parameters.size 30 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 31 | - type: FromCompositeFieldPath 32 | fromFieldPath: spec.parameters.vm 33 | toFieldPath: spec.forProvider.settings.tier 34 | - type: FromCompositeFieldPath 35 | fromFieldPath: metadata.labels[claim.name] 36 | toFieldPath: metadata.annotations[crossplane.io/external-name] 37 | transforms: 38 | - type: string 39 | string: 40 | fmt: "%s-gcp-mysql-cloudsqlinstance" 41 | -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Breaking/Composition-V2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gcp-mysql 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: xrd-breaking.imarunrk.com/v2 8 | kind: XMySql 9 | resources: 10 | - name: cloudsqlinstance 11 | base: 12 | apiVersion: database.gcp.crossplane.io/v1beta1 13 | kind: CloudSQLInstance 14 | spec: 15 | deletionPolicy: Orphan 16 | providerConfigRef: 17 | name: gcp-credentials-project-1 18 | forProvider: 19 | region: us-central1 20 | databaseVersion: MYSQL_5_7 21 | settings: 22 | tier: db-n1-standard-4 23 | dataDiskSizeGb: 40 24 | patches: 25 | - type: FromCompositeFieldPath 26 | fromFieldPath: spec.parameters.size 27 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 28 | - type: FromCompositeFieldPath 29 | fromFieldPath: metadata.labels[claim.name] 30 | toFieldPath: metadata.annotations[crossplane.io/external-name] 31 | transforms: 32 | - type: string 33 | string: 34 | fmt: "%s-gcp-mysql-cloudsqlinstance" -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Breaking/xrd-v1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xmysqls.xrd-breaking.imarunrk.com 5 | spec: 6 | group: xrd-breaking.imarunrk.com 7 | names: 8 | kind: XMySql 9 | plural: xmysqls 10 | claimNames: 11 | kind: MySql 12 | plural: mysqls 13 | versions: 14 | - name: v1 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | size: 28 | type: integer 29 | vm: 30 | type: string 31 | required: 32 | - vm 33 | required: 34 | - parameters -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Breaking/xrd-v2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xmysqls.xrd-breaking.imarunrk.com 5 | spec: 6 | group: xrd-breaking.imarunrk.com 7 | names: 8 | kind: XMySql 9 | plural: xmysqls 10 | claimNames: 11 | kind: MySql 12 | plural: mysqls 13 | versions: 14 | - name: v2 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | size: 28 | type: integer -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Non-Breaking/Claim-v1-validate.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: xrd-non-breaking.imarunrk.com/v1 2 | kind: MySql 3 | metadata: 4 | namespace: alpha 5 | name: mysql-db-v1 6 | spec: 7 | compositionRef: 8 | name: gcp-mysql 9 | parameters: 10 | vm: db-n1-standard-4 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Non-Breaking/Claim-v1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: xrd-non-breaking.imarunrk.com/v1 2 | kind: MySql 3 | metadata: 4 | namespace: alpha 5 | name: mysql-db-v1 6 | spec: 7 | compositionRef: 8 | name: gcp-mysql 9 | parameters: 10 | vm: db-n1-standard-1 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Non-Breaking/Claim-v2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: xrd-non-breaking.imarunrk.com/v1 2 | kind: MySql 3 | metadata: 4 | namespace: alpha 5 | name: mysql-db-v2 6 | spec: 7 | compositionRef: 8 | name: gcp-mysql 9 | parameters: 10 | size: 10 11 | vm: db-n1-standard-2 -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Non-Breaking/Composition-V1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gcp-mysql 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: xrd-non-breaking.imarunrk.com/v1 8 | kind: XMySql 9 | resources: 10 | - name: cloudsqlinstance 11 | base: 12 | apiVersion: database.gcp.crossplane.io/v1beta1 13 | kind: CloudSQLInstance 14 | spec: 15 | providerConfigRef: 16 | name: gcp-credentials-project-1 17 | forProvider: 18 | region: us-central1 19 | databaseVersion: MYSQL_5_7 20 | settings: 21 | tier: db-g1-small 22 | dataDiskSizeGb: 40 23 | patches: 24 | - type: FromCompositeFieldPath 25 | fromFieldPath: spec.parameters.vm 26 | toFieldPath: spec.forProvider.settings.tier 27 | -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Non-Breaking/Composition-V2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gcp-mysql 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: xrd-non-breaking.imarunrk.com/v1 8 | kind: XMySql 9 | resources: 10 | - name: cloudsqlinstance 11 | base: 12 | apiVersion: database.gcp.crossplane.io/v1beta1 13 | kind: CloudSQLInstance 14 | spec: 15 | providerConfigRef: 16 | name: gcp-credentials-project-1 17 | forProvider: 18 | region: us-central1 19 | databaseVersion: MYSQL_5_7 20 | settings: 21 | tier: db-g1-small 22 | dataDiskSizeGb: 40 23 | patches: 24 | - type: FromCompositeFieldPath 25 | fromFieldPath: spec.parameters.size 26 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 27 | - type: FromCompositeFieldPath 28 | fromFieldPath: spec.parameters.vm 29 | toFieldPath: spec.forProvider.settings.tier -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Non-Breaking/xrd-v1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xmysqls.xrd-non-breaking.imarunrk.com 5 | spec: 6 | group: xrd-non-breaking.imarunrk.com 7 | names: 8 | kind: XMySql 9 | plural: xmysqls 10 | claimNames: 11 | kind: MySql 12 | plural: mysqls 13 | versions: 14 | - name: v1 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | vm: 28 | type: string 29 | required: 30 | - vm 31 | required: 32 | - parameters -------------------------------------------------------------------------------- /Chapter05/Hand-on-examples/XRD-Contract-Change-Non-Breaking/xrd-v2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xmysqls.xrd-non-breaking.imarunrk.com 5 | spec: 6 | group: xrd-non-breaking.imarunrk.com 7 | names: 8 | kind: XMySql 9 | plural: xmysqls 10 | claimNames: 11 | kind: MySql 12 | plural: mysqls 13 | versions: 14 | - name: v1 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | size: 28 | type: integer 29 | vm: 30 | type: string 31 | required: 32 | - vm 33 | required: 34 | - parameters -------------------------------------------------------------------------------- /Chapter05/Samples/XRD-Versions/xrd-invalid-version-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xbuckets.version-test.imarunrk.com 5 | spec: 6 | group: version-test.imarunrk.com 7 | names: 8 | kind: XBuckets 9 | plural: xbuckets 10 | versions: 11 | - name: v1.0 12 | served: true 13 | referenceable: true 14 | schema: 15 | openAPIV3Schema: 16 | type: object 17 | properties: 18 | spec: 19 | type: object 20 | properties: 21 | parameters: 22 | type: object 23 | properties: 24 | region: 25 | type: string 26 | required: 27 | - region 28 | required: 29 | - parameters -------------------------------------------------------------------------------- /Chapter05/Samples/XRD-Versions/xrd-multiple-version.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xversiontests.xrd-version.imarunrk.com 5 | spec: 6 | group: xrd-version.imarunrk.com 7 | names: 8 | kind: XVersionTest 9 | plural: xversiontests 10 | claimNames: 11 | kind: VersionTest 12 | plural: versiontests 13 | versions: 14 | - name: v1 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | size: 28 | type: integer 29 | required: 30 | - size 31 | required: 32 | - parameters 33 | - name: alpha 34 | served: false 35 | referenceable: false 36 | schema: 37 | openAPIV3Schema: 38 | type: object 39 | properties: 40 | spec: 41 | type: object 42 | properties: 43 | parameters: 44 | type: object 45 | properties: 46 | size: 47 | type: integer 48 | required: 49 | - size 50 | required: 51 | - parameters 52 | - name: beta 53 | served: true 54 | referenceable: false 55 | schema: 56 | openAPIV3Schema: 57 | type: object 58 | properties: 59 | spec: 60 | type: object 61 | properties: 62 | parameters: 63 | type: object 64 | properties: 65 | size: 66 | type: integer 67 | required: 68 | - size 69 | required: 70 | - parameters -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/aws-setup/AWS-Provider.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1alpha1 2 | kind: ControllerConfig 3 | metadata: 4 | name: debug-config 5 | spec: 6 | args: 7 | - --debug 8 | --- 9 | apiVersion: pkg.crossplane.io/v1 10 | kind: Provider 11 | metadata: 12 | name: provider-aws 13 | spec: 14 | package: "crossplane/provider-aws:v0.24.1" 15 | controllerConfigRef: 16 | name: debug-config -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/aws-setup/AWS-cli-install.md: -------------------------------------------------------------------------------- 1 | # AWS CLI install instructions 2 | 3 | https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/aws-setup/AWS-kubernetes-credential.md: -------------------------------------------------------------------------------- 1 | # Configure a AWS profile named crossplane 2 | # This ask for the access key, access secret, default region and cli output format 3 | aws configure --profile default 4 | 5 | # set a variable with the profile name 6 | AWS_PROFILE=default 7 | 8 | # Create a configuration file with profile created 9 | echo -e "[$AWS_PROFILE]\naws_access_key_id = $(aws configure get aws_access_key_id --profile $AWS_PROFILE)\naws_secret_access_key = $(aws configure get aws_secret_access_key --profile $AWS_PROFILE)" > aws-credentials.conf 10 | 11 | # Create kubernetes secret from the configuration file 12 | kubectl create secret generic aws-credentials -n crossplane-system --from-file=creds=./aws-credentials.conf -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/aws-setup/Provider-Config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: aws.crossplane.io/v1beta1 2 | kind: ProviderConfig 3 | metadata: 4 | name: aws-credentials 5 | spec: 6 | credentials: 7 | source: Secret 8 | secretRef: 9 | namespace: crossplane-system 10 | name: aws-credentials 11 | key: creds -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/aws-setup/rds.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: database.aws.crossplane.io/v1beta1 2 | kind: RDSInstance 3 | metadata: 4 | name: rdspostgresql 5 | spec: 6 | providerConfigRef: 7 | name: aws-credentials 8 | forProvider: 9 | region: ap-south-1 10 | dbInstanceClass: db.t2.small 11 | masterUsername: master 12 | allocatedStorage: 10 13 | engine: postgres 14 | engineVersion: "12" 15 | skipFinalSnapshotBeforeDeletion: true 16 | writeConnectionSecretToRef: 17 | namespace: crossplane-system 18 | name: rds-conn -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/different-xr-reference/claim-bucket.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: differentxr.reference.imarunrk.com/v1 2 | kind: MyBucket 3 | metadata: 4 | namespace: alpha 5 | name: my-bucket 6 | spec: 7 | compositionRef: 8 | name: my-bucket 9 | parameters: 10 | bucketName: test-reference-bucket-arun -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/different-xr-reference/claim-iam.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: differentxr.reference.imarunrk.com/v1 2 | kind: IAMResourceUser 3 | metadata: 4 | namespace: alpha 5 | name: iam-user 6 | spec: 7 | compositionRef: 8 | name: resource-iam 9 | parameters: 10 | resourceName: test-reference-bucket-arun 11 | resourceType: bucket -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/different-xr-reference/composition-IAM.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: resource-iam 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: differentxr.reference.imarunrk.com/v1 8 | kind: XIAMResourceUser 9 | resources: 10 | # Create IAM user 11 | - base: 12 | apiVersion: iam.aws.crossplane.io/v1beta1 13 | kind: User 14 | spec: 15 | providerConfigRef: 16 | name: aws-credentials 17 | forProvider: 18 | path: "/" 19 | patches: 20 | # patch the name of IAM user with dynamic placeholder 21 | # user-- 22 | - type: CombineFromComposite 23 | toFieldPath: metadata.name 24 | combine: 25 | variables: 26 | - fromFieldPath: spec.parameters.resourceType 27 | - fromFieldPath: spec.parameters.resourceName 28 | strategy: string 29 | string: 30 | fmt: "user-%s-%s" 31 | # Attach the resource policy with the IAM User 32 | - base: 33 | apiVersion: iam.aws.crossplane.io/v1beta1 34 | kind: UserPolicyAttachment 35 | spec: 36 | providerConfigRef: 37 | name: aws-credentials 38 | forProvider: 39 | # refer to the IAM user from the same composition using matchControllerRef 40 | userNameSelector: 41 | matchControllerRef: true 42 | policyArnSelector: 43 | matchControllerRef: false 44 | patches: 45 | # Patch the policy ARN lable 1 46 | - toFieldPath: spec.forProvider.policyArnSelector.matchLabels.resourceName 47 | fromFieldPath: spec.parameters.resourceName 48 | # Patch the policy ARN lable 2 49 | - toFieldPath: spec.forProvider.policyArnSelector.matchLabels.resourceType 50 | fromFieldPath: spec.parameters.resourceType 51 | # Patch the policy resource name with standerd name construction 52 | # -- 53 | - type: CombineFromComposite 54 | toFieldPath: metadata.name 55 | combine: 56 | variables: 57 | - fromFieldPath: spec.parameters.resourceType 58 | - fromFieldPath: spec.parameters.resourceName 59 | strategy: string 60 | string: 61 | fmt: "policy-attachement-%s-%s" -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/different-xr-reference/composition-bucket.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: my-bucket 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: differentxr.reference.imarunrk.com/v1 8 | kind: XMyBucket 9 | resources: 10 | # Create the bucket resource 11 | - base: 12 | apiVersion: s3.aws.crossplane.io/v1beta1 13 | kind: Bucket 14 | spec: 15 | providerConfigRef: 16 | name: aws-credentials 17 | forProvider: 18 | acl: private 19 | locationConstraint: ap-south-1 20 | patches: 21 | # patch the name of the bucket 22 | - fromFieldPath: spec.parameters.bucketName 23 | toFieldPath: metadata.name 24 | # Define IAM policy resource for the bucket 25 | # Naming pattern: -- 26 | - base: 27 | apiVersion: iam.aws.crossplane.io/v1beta1 28 | kind: Policy 29 | metadata: 30 | # Add labels one as the resource type 31 | labels: 32 | resourceType: bucket 33 | spec: 34 | providerConfigRef: 35 | name: aws-credentials 36 | forProvider: 37 | path: "/" 38 | patches: 39 | # patch labels two from the resource name 40 | - fromFieldPath: spec.parameters.bucketName 41 | toFieldPath: metadata.labels[resourceName] 42 | # patch the MR name with the bucket name with prefix 43 | - fromFieldPath: spec.parameters.bucketName 44 | toFieldPath: metadata.name 45 | transforms: 46 | - type: string 47 | string: 48 | fmt: "policy-bucket-%s" 49 | # patch the policy name with the bucket name with prefix 50 | - fromFieldPath: spec.parameters.bucketName 51 | toFieldPath: spec.forProvider.name 52 | transforms: 53 | - type: string 54 | string: 55 | fmt: "policy-bucket-%s" 56 | # Patch the policy Json 57 | # Full access policy for specific S3 resource 58 | - type: CombineFromComposite 59 | toFieldPath: spec.forProvider.document 60 | combine: 61 | variables: 62 | - fromFieldPath: spec.parameters.bucketName 63 | - fromFieldPath: spec.parameters.bucketName 64 | strategy: string 65 | string: 66 | fmt: | 67 | { 68 | "Version": "2012-10-17", 69 | "Statement": [ 70 | { 71 | "Effect": "Allow", 72 | "Action": [ "s3:*" ], 73 | "Resource": [ 74 | "arn:aws:s3:::%s", 75 | "arn:aws:s3:::%s/*" 76 | ] 77 | } 78 | ] 79 | } -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/different-xr-reference/xrd-IAM.yaml: -------------------------------------------------------------------------------- 1 | # XRD for an XR API to create a IAM user with a specific resource access 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: xiamresourceusers.differentxr.reference.imarunrk.com 6 | spec: 7 | group: differentxr.reference.imarunrk.com 8 | names: 9 | kind: XIAMResourceUser 10 | plural: xiamresourceusers 11 | claimNames: 12 | kind: IAMResourceUser 13 | plural: iamresourceusers 14 | versions: 15 | - name: v1 16 | served: true 17 | referenceable: true 18 | schema: 19 | openAPIV3Schema: 20 | type: object 21 | properties: 22 | # Resource name, type and policy arn as API input 23 | spec: 24 | type: object 25 | properties: 26 | parameters: 27 | type: object 28 | properties: 29 | resourceName: 30 | description: The name that is used for IAM user creation. User the same name as resource name for resource policy lookup to work. 31 | type: string 32 | resourceType: 33 | description: A string used as a part of prefix in IAM creation. 34 | type: string 35 | required: 36 | - resourceName 37 | - resourceType 38 | required: 39 | - parameters -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/different-xr-reference/xrd-bucket.yaml: -------------------------------------------------------------------------------- 1 | # XRD for an API to create a bucket with and a IAM user for bucket access 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: xmybuckets.differentxr.reference.imarunrk.com 6 | spec: 7 | group: differentxr.reference.imarunrk.com 8 | names: 9 | kind: XMyBucket 10 | plural: xmybuckets 11 | claimNames: 12 | kind: MyBucket 13 | plural: mybuckets 14 | versions: 15 | - name: v1 16 | served: true 17 | referenceable: true 18 | schema: 19 | openAPIV3Schema: 20 | type: object 21 | properties: 22 | # S3 bucket name is the API input 23 | spec: 24 | type: object 25 | properties: 26 | parameters: 27 | type: object 28 | properties: 29 | bucketName: 30 | description: The name of the S3 bucket 31 | type: string 32 | required: 33 | - bucketName 34 | required: 35 | - parameters -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/helm-provider/GKE.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: container.gcp.crossplane.io/v1beta2 2 | kind: Cluster 3 | metadata: 4 | name: gke-for-helm-deployment 5 | spec: 6 | providerConfigRef: 7 | name: gcp-credentials-project-1 8 | forProvider: 9 | location: us-west2 10 | loggingService: logging.googleapis.com/kubernetes 11 | monitoringService: monitoring.googleapis.com/kubernetes 12 | writeConnectionSecretToRef: 13 | namespace: crossplane-system 14 | name: secret-gke-for-helm-deployment 15 | --- 16 | apiVersion: container.gcp.crossplane.io/v1beta1 17 | kind: NodePool 18 | metadata: 19 | name: gke-node-for-helm-deployment 20 | spec: 21 | providerConfigRef: 22 | name: gcp-credentials-project-1 23 | forProvider: 24 | autoscaling: 25 | autoprovisioned: false 26 | enabled: true 27 | maxNodeCount: 4 28 | minNodeCount: 4 29 | clusterRef: 30 | name: gke-for-helm-deployment 31 | config: 32 | machineType: e2-medium 33 | initialNodeCount: 4 34 | locations: 35 | - "us-west2-a" -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/helm-provider/Helm-Provider.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: provider-helm 5 | spec: 6 | package: crossplane/provider-helm:master -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/helm-provider/Helm-test-deploy-upgrade.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: helm.crossplane.io/v1beta1 2 | kind: Release 3 | metadata: 4 | name: helm-crossplane-example 5 | spec: 6 | providerConfigRef: 7 | name: helm-provider 8 | forProvider: 9 | chart: 10 | name: hello 11 | repository: https://www.kleinloog.ch/hello-helm/ 12 | version: 0.4.0-rc2 13 | namespace: default -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/helm-provider/Helm-test-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: helm.crossplane.io/v1beta1 2 | kind: Release 3 | metadata: 4 | name: helm-crossplane-example 5 | spec: 6 | providerConfigRef: 7 | name: helm-provider 8 | forProvider: 9 | chart: 10 | name: hello 11 | repository: https://www.kleinloog.ch/hello-helm/ 12 | version: 0.3.0 13 | namespace: default -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/helm-provider/Provider-Config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: helm.crossplane.io/v1beta1 2 | kind: ProviderConfig 3 | metadata: 4 | name: helm-provider 5 | spec: 6 | credentials: 7 | source: Secret 8 | secretRef: 9 | name: secret-gke-for-helm-deployment 10 | namespace: crossplane-system 11 | key: kubeconfig 12 | identity: 13 | type: GoogleApplicationCredentials 14 | source: Secret 15 | secretRef: 16 | name: gcp-account 17 | namespace: crossplane-system 18 | key: service-account -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/monitoring/GCP-Provider.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: pkg.crossplane.io/v1alpha1 3 | kind: ControllerConfig 4 | metadata: 5 | name: allow-prometheus 6 | spec: 7 | metadata: 8 | labels: 9 | crossplane.io/provider: "true" 10 | ports: 11 | - name: metrics 12 | containerPort: 8080 13 | --- 14 | apiVersion: pkg.crossplane.io/v1 15 | kind: Provider 16 | metadata: 17 | name: provider-gcp 18 | spec: 19 | package: crossplane/provider-gcp:v0.18.0 20 | controllerConfigRef: 21 | name: allow-prometheus -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/monitoring/SQL.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: database.gcp.crossplane.io/v1beta1 2 | kind: CloudSQLInstance 3 | metadata: 4 | name: db-gcp-new 5 | spec: 6 | providerConfigRef: 7 | name: gcp-credentials-project-1 8 | writeConnectionSecretToRef: 9 | namespace: crossplane-system 10 | name: db-ssdss 11 | forProvider: 12 | databaseVersion: POSTGRES_9_621 13 | region: us-central 14 | settings: 15 | tier: db-g1-small 16 | dataDiskSizeGb: 20 -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/monitoring/alert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: PrometheusRule 3 | metadata: 4 | name: sql-alerts 5 | namespace: crossplane-system 6 | labels: 7 | app.kubernetes.io/part-of: crossplane 8 | spec: 9 | groups: 10 | - name: Crossplane 11 | rules: 12 | - alert: ReconciliationFailure 13 | expr: sum_over_time(controller_runtime_reconcile_errors_total{namespace="crossplane-system", controller="managed/cloudsqlinstance.database.gcp.crossplane.io"}[5m]) > 20 14 | for: 5m 15 | labels: 16 | severity: page 17 | annotations: 18 | summary: '{{ $labels.controller }} reconciliation has been failing for more than 20 time in the last 5 minutes.' -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/monitoring/grafana.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "target": { 12 | "limit": 100, 13 | "matchAny": false, 14 | "tags": [], 15 | "type": "dashboard" 16 | }, 17 | "type": "dashboard" 18 | } 19 | ] 20 | }, 21 | "editable": true, 22 | "gnetId": null, 23 | "graphTooltip": 0, 24 | "id": 25, 25 | "links": [], 26 | "panels": [ 27 | { 28 | "datasource": null, 29 | "gridPos": { 30 | "h": 1, 31 | "w": 24, 32 | "x": 0, 33 | "y": 0 34 | }, 35 | "id": 28, 36 | "title": "Row title", 37 | "type": "row" 38 | }, 39 | { 40 | "collapsed": true, 41 | "datasource": null, 42 | "gridPos": { 43 | "h": 1, 44 | "w": 24, 45 | "x": 0, 46 | "y": 1 47 | }, 48 | "id": 16, 49 | "panels": [ 50 | { 51 | "datasource": "prometheus", 52 | "fieldConfig": { 53 | "defaults": { 54 | "color": { 55 | "mode": "palette-classic" 56 | }, 57 | "custom": { 58 | "axisLabel": "", 59 | "axisPlacement": "auto", 60 | "barAlignment": 0, 61 | "drawStyle": "line", 62 | "fillOpacity": 20, 63 | "gradientMode": "none", 64 | "hideFrom": { 65 | "legend": false, 66 | "tooltip": false, 67 | "viz": false 68 | }, 69 | "lineInterpolation": "linear", 70 | "lineWidth": 1, 71 | "pointSize": 5, 72 | "scaleDistribution": { 73 | "type": "linear" 74 | }, 75 | "showPoints": "auto", 76 | "spanNulls": false, 77 | "stacking": { 78 | "group": "A", 79 | "mode": "normal" 80 | }, 81 | "thresholdsStyle": { 82 | "mode": "off" 83 | } 84 | }, 85 | "mappings": [], 86 | "thresholds": { 87 | "mode": "absolute", 88 | "steps": [ 89 | { 90 | "color": "green", 91 | "value": null 92 | }, 93 | { 94 | "color": "red", 95 | "value": 80 96 | } 97 | ] 98 | }, 99 | "unit": "ops" 100 | }, 101 | "overrides": [] 102 | }, 103 | "gridPos": { 104 | "h": 6, 105 | "w": 14, 106 | "x": 0, 107 | "y": 1 108 | }, 109 | "id": 13, 110 | "options": { 111 | "legend": { 112 | "calcs": [], 113 | "displayMode": "hidden", 114 | "placement": "bottom" 115 | }, 116 | "tooltip": { 117 | "mode": "multi" 118 | } 119 | }, 120 | "targets": [ 121 | { 122 | "exemplar": true, 123 | "expr": "sum by (reason) (rate(kube_event_count{type=\"Normal\"}[$__rate_interval]))", 124 | "interval": "", 125 | "legendFormat": "{{reason}}", 126 | "queryType": "randomWalk", 127 | "refId": "A" 128 | } 129 | ], 130 | "title": "Normal Events by Reason", 131 | "type": "timeseries" 132 | }, 133 | { 134 | "datasource": "prometheus", 135 | "fieldConfig": { 136 | "defaults": { 137 | "color": { 138 | "mode": "palette-classic" 139 | }, 140 | "custom": { 141 | "axisLabel": "", 142 | "axisPlacement": "auto", 143 | "barAlignment": 0, 144 | "drawStyle": "line", 145 | "fillOpacity": 20, 146 | "gradientMode": "none", 147 | "hideFrom": { 148 | "legend": false, 149 | "tooltip": false, 150 | "viz": false 151 | }, 152 | "lineInterpolation": "linear", 153 | "lineWidth": 1, 154 | "pointSize": 5, 155 | "scaleDistribution": { 156 | "type": "linear" 157 | }, 158 | "showPoints": "auto", 159 | "spanNulls": false, 160 | "stacking": { 161 | "group": "A", 162 | "mode": "normal" 163 | }, 164 | "thresholdsStyle": { 165 | "mode": "off" 166 | } 167 | }, 168 | "mappings": [], 169 | "thresholds": { 170 | "mode": "absolute", 171 | "steps": [ 172 | { 173 | "color": "green", 174 | "value": null 175 | }, 176 | { 177 | "color": "red", 178 | "value": 80 179 | } 180 | ] 181 | }, 182 | "unit": "ops" 183 | }, 184 | "overrides": [] 185 | }, 186 | "gridPos": { 187 | "h": 6, 188 | "w": 10, 189 | "x": 14, 190 | "y": 1 191 | }, 192 | "id": 14, 193 | "options": { 194 | "legend": { 195 | "calcs": [], 196 | "displayMode": "hidden", 197 | "placement": "bottom" 198 | }, 199 | "tooltip": { 200 | "mode": "single" 201 | } 202 | }, 203 | "targets": [ 204 | { 205 | "exemplar": true, 206 | "expr": "sum by (reason) (rate(kube_event_count{type=\"Warning\"}[$__rate_interval]))", 207 | "interval": "", 208 | "legendFormat": "{{reason}}", 209 | "queryType": "randomWalk", 210 | "refId": "A" 211 | } 212 | ], 213 | "title": "Warning Events by Reason", 214 | "type": "timeseries" 215 | } 216 | ], 217 | "title": "Events", 218 | "type": "row" 219 | }, 220 | { 221 | "collapsed": true, 222 | "datasource": null, 223 | "gridPos": { 224 | "h": 1, 225 | "w": 24, 226 | "x": 0, 227 | "y": 2 228 | }, 229 | "id": 20, 230 | "panels": [ 231 | { 232 | "datasource": "prometheus", 233 | "fieldConfig": { 234 | "defaults": { 235 | "color": { 236 | "mode": "palette-classic" 237 | }, 238 | "custom": { 239 | "axisLabel": "", 240 | "axisPlacement": "auto", 241 | "barAlignment": 0, 242 | "drawStyle": "line", 243 | "fillOpacity": 20, 244 | "gradientMode": "none", 245 | "hideFrom": { 246 | "legend": false, 247 | "tooltip": false, 248 | "viz": false 249 | }, 250 | "lineInterpolation": "linear", 251 | "lineWidth": 1, 252 | "pointSize": 5, 253 | "scaleDistribution": { 254 | "type": "linear" 255 | }, 256 | "showPoints": "auto", 257 | "spanNulls": false, 258 | "stacking": { 259 | "group": "A", 260 | "mode": "normal" 261 | }, 262 | "thresholdsStyle": { 263 | "mode": "off" 264 | } 265 | }, 266 | "mappings": [], 267 | "thresholds": { 268 | "mode": "absolute", 269 | "steps": [ 270 | { 271 | "color": "green", 272 | "value": null 273 | }, 274 | { 275 | "color": "red", 276 | "value": 80 277 | } 278 | ] 279 | }, 280 | "unit": "ops" 281 | }, 282 | "overrides": [] 283 | }, 284 | "gridPos": { 285 | "h": 8, 286 | "w": 7, 287 | "x": 0, 288 | "y": 2 289 | }, 290 | "id": 7, 291 | "options": { 292 | "legend": { 293 | "calcs": [], 294 | "displayMode": "hidden", 295 | "placement": "bottom" 296 | }, 297 | "tooltip": { 298 | "mode": "multi" 299 | } 300 | }, 301 | "targets": [ 302 | { 303 | "exemplar": true, 304 | "expr": "topk(10, sum by (controller) (rate(controller_runtime_reconcile_total{job=~\"crossplane-system/.*\"}[$__rate_interval])))", 305 | "interval": "", 306 | "intervalFactor": 1, 307 | "legendFormat": "{{controller}}", 308 | "queryType": "randomWalk", 309 | "refId": "A" 310 | } 311 | ], 312 | "title": "Reconciles by Controller (Top 10)", 313 | "type": "timeseries" 314 | }, 315 | { 316 | "datasource": "prometheus", 317 | "fieldConfig": { 318 | "defaults": { 319 | "color": { 320 | "mode": "palette-classic" 321 | }, 322 | "custom": { 323 | "axisLabel": "", 324 | "axisPlacement": "auto", 325 | "barAlignment": 0, 326 | "drawStyle": "line", 327 | "fillOpacity": 20, 328 | "gradientMode": "none", 329 | "hideFrom": { 330 | "legend": false, 331 | "tooltip": false, 332 | "viz": false 333 | }, 334 | "lineInterpolation": "linear", 335 | "lineWidth": 1, 336 | "pointSize": 5, 337 | "scaleDistribution": { 338 | "type": "linear" 339 | }, 340 | "showPoints": "auto", 341 | "spanNulls": false, 342 | "stacking": { 343 | "group": "A", 344 | "mode": "normal" 345 | }, 346 | "thresholdsStyle": { 347 | "mode": "off" 348 | } 349 | }, 350 | "mappings": [], 351 | "thresholds": { 352 | "mode": "absolute", 353 | "steps": [ 354 | { 355 | "color": "green", 356 | "value": null 357 | }, 358 | { 359 | "color": "red", 360 | "value": 80 361 | } 362 | ] 363 | }, 364 | "unit": "reqps" 365 | }, 366 | "overrides": [] 367 | }, 368 | "gridPos": { 369 | "h": 8, 370 | "w": 8, 371 | "x": 7, 372 | "y": 2 373 | }, 374 | "id": 22, 375 | "options": { 376 | "legend": { 377 | "calcs": [], 378 | "displayMode": "hidden", 379 | "placement": "bottom" 380 | }, 381 | "tooltip": { 382 | "mode": "multi" 383 | } 384 | }, 385 | "targets": [ 386 | { 387 | "exemplar": true, 388 | "expr": "sum by (job) (rate(rest_client_requests_total{job=~\"crossplane-system/.*\"}[$__rate_interval]))", 389 | "interval": "", 390 | "legendFormat": "{{job}}", 391 | "queryType": "randomWalk", 392 | "refId": "A" 393 | } 394 | ], 395 | "title": "API Server Requests", 396 | "type": "timeseries" 397 | }, 398 | { 399 | "datasource": "prometheus", 400 | "fieldConfig": { 401 | "defaults": { 402 | "color": { 403 | "mode": "palette-classic" 404 | }, 405 | "custom": { 406 | "axisLabel": "", 407 | "axisPlacement": "auto", 408 | "barAlignment": 0, 409 | "drawStyle": "line", 410 | "fillOpacity": 0, 411 | "gradientMode": "none", 412 | "hideFrom": { 413 | "legend": false, 414 | "tooltip": false, 415 | "viz": false 416 | }, 417 | "lineInterpolation": "linear", 418 | "lineWidth": 1, 419 | "pointSize": 5, 420 | "scaleDistribution": { 421 | "type": "linear" 422 | }, 423 | "showPoints": "auto", 424 | "spanNulls": false, 425 | "stacking": { 426 | "group": "A", 427 | "mode": "none" 428 | }, 429 | "thresholdsStyle": { 430 | "mode": "off" 431 | } 432 | }, 433 | "mappings": [], 434 | "thresholds": { 435 | "mode": "absolute", 436 | "steps": [ 437 | { 438 | "color": "green", 439 | "value": null 440 | }, 441 | { 442 | "color": "red", 443 | "value": 80 444 | } 445 | ] 446 | } 447 | }, 448 | "overrides": [] 449 | }, 450 | "gridPos": { 451 | "h": 4, 452 | "w": 9, 453 | "x": 15, 454 | "y": 2 455 | }, 456 | "id": 9, 457 | "options": { 458 | "legend": { 459 | "calcs": [], 460 | "displayMode": "hidden", 461 | "placement": "bottom" 462 | }, 463 | "tooltip": { 464 | "mode": "multi" 465 | } 466 | }, 467 | "targets": [ 468 | { 469 | "exemplar": true, 470 | "expr": "topk(10, sum by (name) (workqueue_depth{job=~\"crossplane-system/.+\"}))", 471 | "interval": "", 472 | "intervalFactor": 1, 473 | "legendFormat": "{{name}}", 474 | "queryType": "randomWalk", 475 | "refId": "A" 476 | } 477 | ], 478 | "title": "Workqueue Depth by Controller (Top 10)", 479 | "type": "timeseries" 480 | }, 481 | { 482 | "cards": { 483 | "cardPadding": null, 484 | "cardRound": null 485 | }, 486 | "color": { 487 | "cardColor": "#FF9830", 488 | "colorScale": "sqrt", 489 | "colorScheme": "interpolateOranges", 490 | "exponent": 0.5, 491 | "mode": "opacity" 492 | }, 493 | "dataFormat": "tsbuckets", 494 | "datasource": "prometheus", 495 | "gridPos": { 496 | "h": 4, 497 | "w": 9, 498 | "x": 15, 499 | "y": 6 500 | }, 501 | "heatmap": {}, 502 | "hideZeroBuckets": false, 503 | "highlightCards": true, 504 | "id": 11, 505 | "legend": { 506 | "show": false 507 | }, 508 | "maxDataPoints": 50, 509 | "reverseYBuckets": false, 510 | "targets": [ 511 | { 512 | "exemplar": true, 513 | "expr": "sum(rate(workqueue_queue_duration_seconds_bucket{job=~\"crossplane-system/.+\"}[$__rate_interval])) by (le)", 514 | "format": "heatmap", 515 | "interval": "", 516 | "legendFormat": "{{le}}", 517 | "queryType": "randomWalk", 518 | "refId": "A" 519 | } 520 | ], 521 | "title": "Workqueue Duration", 522 | "tooltip": { 523 | "show": true, 524 | "showHistogram": false 525 | }, 526 | "type": "heatmap", 527 | "xAxis": { 528 | "show": true 529 | }, 530 | "xBucketNumber": null, 531 | "xBucketSize": null, 532 | "yAxis": { 533 | "decimals": 2, 534 | "format": "s", 535 | "logBase": 1, 536 | "max": null, 537 | "min": null, 538 | "show": true, 539 | "splitFactor": null 540 | }, 541 | "yBucketBound": "auto", 542 | "yBucketNumber": null, 543 | "yBucketSize": null 544 | } 545 | ], 546 | "title": "Crossplane", 547 | "type": "row" 548 | }, 549 | { 550 | "collapsed": false, 551 | "datasource": null, 552 | "gridPos": { 553 | "h": 1, 554 | "w": 24, 555 | "x": 0, 556 | "y": 3 557 | }, 558 | "id": 18, 559 | "panels": [], 560 | "title": "API Server", 561 | "type": "row" 562 | }, 563 | { 564 | "datasource": "prometheus", 565 | "description": "", 566 | "fieldConfig": { 567 | "defaults": { 568 | "color": { 569 | "mode": "palette-classic" 570 | }, 571 | "custom": { 572 | "axisLabel": "", 573 | "axisPlacement": "auto", 574 | "barAlignment": 0, 575 | "drawStyle": "line", 576 | "fillOpacity": 20, 577 | "gradientMode": "none", 578 | "hideFrom": { 579 | "legend": false, 580 | "tooltip": false, 581 | "viz": false 582 | }, 583 | "lineInterpolation": "linear", 584 | "lineStyle": { 585 | "fill": "solid" 586 | }, 587 | "lineWidth": 1, 588 | "pointSize": 5, 589 | "scaleDistribution": { 590 | "type": "linear" 591 | }, 592 | "showPoints": "auto", 593 | "spanNulls": false, 594 | "stacking": { 595 | "group": "A", 596 | "mode": "normal" 597 | }, 598 | "thresholdsStyle": { 599 | "mode": "off" 600 | } 601 | }, 602 | "mappings": [], 603 | "thresholds": { 604 | "mode": "absolute", 605 | "steps": [ 606 | { 607 | "color": "green", 608 | "value": null 609 | }, 610 | { 611 | "color": "red", 612 | "value": 80 613 | } 614 | ] 615 | }, 616 | "unit": "reqps" 617 | }, 618 | "overrides": [] 619 | }, 620 | "gridPos": { 621 | "h": 8, 622 | "w": 9, 623 | "x": 0, 624 | "y": 4 625 | }, 626 | "id": 2, 627 | "options": { 628 | "legend": { 629 | "calcs": [], 630 | "displayMode": "hidden", 631 | "placement": "bottom" 632 | }, 633 | "tooltip": { 634 | "mode": "multi" 635 | } 636 | }, 637 | "targets": [ 638 | { 639 | "exemplar": true, 640 | "expr": "topk(10, sum by (resource) (rate(apiserver_request_total[$__rate_interval])))", 641 | "interval": "", 642 | "intervalFactor": 1, 643 | "legendFormat": "{{resource}}", 644 | "queryType": "randomWalk", 645 | "refId": "A" 646 | } 647 | ], 648 | "title": "API Server Requests by Resource (Top 10)", 649 | "type": "timeseries" 650 | }, 651 | { 652 | "datasource": "prometheus", 653 | "fieldConfig": { 654 | "defaults": { 655 | "color": { 656 | "mode": "palette-classic" 657 | }, 658 | "custom": { 659 | "axisLabel": "", 660 | "axisPlacement": "auto", 661 | "barAlignment": 0, 662 | "drawStyle": "line", 663 | "fillOpacity": 20, 664 | "gradientMode": "none", 665 | "hideFrom": { 666 | "legend": false, 667 | "tooltip": false, 668 | "viz": false 669 | }, 670 | "lineInterpolation": "linear", 671 | "lineWidth": 1, 672 | "pointSize": 5, 673 | "scaleDistribution": { 674 | "type": "linear" 675 | }, 676 | "showPoints": "auto", 677 | "spanNulls": false, 678 | "stacking": { 679 | "group": "A", 680 | "mode": "normal" 681 | }, 682 | "thresholdsStyle": { 683 | "mode": "off" 684 | } 685 | }, 686 | "mappings": [], 687 | "thresholds": { 688 | "mode": "absolute", 689 | "steps": [ 690 | { 691 | "color": "green", 692 | "value": null 693 | }, 694 | { 695 | "color": "red", 696 | "value": 80 697 | } 698 | ] 699 | }, 700 | "unit": "reqps" 701 | }, 702 | "overrides": [] 703 | }, 704 | "gridPos": { 705 | "h": 8, 706 | "w": 8, 707 | "x": 9, 708 | "y": 4 709 | }, 710 | "id": 3, 711 | "options": { 712 | "legend": { 713 | "calcs": [], 714 | "displayMode": "hidden", 715 | "placement": "bottom" 716 | }, 717 | "tooltip": { 718 | "mode": "single" 719 | } 720 | }, 721 | "targets": [ 722 | { 723 | "exemplar": true, 724 | "expr": "sum by (code, resource) (rate(apiserver_request_total{code=~\"[45][0-9][0-9]\"}[$__rate_interval]))", 725 | "interval": "", 726 | "legendFormat": "{{code}} ({{resource}})", 727 | "queryType": "randomWalk", 728 | "refId": "A" 729 | } 730 | ], 731 | "title": "API Server Errors by Resource and Code", 732 | "type": "timeseries" 733 | }, 734 | { 735 | "cards": { 736 | "cardPadding": null, 737 | "cardRound": null 738 | }, 739 | "color": { 740 | "cardColor": "#F2495C", 741 | "colorScale": "sqrt", 742 | "colorScheme": "interpolateOranges", 743 | "exponent": 0.5, 744 | "mode": "opacity" 745 | }, 746 | "dataFormat": "tsbuckets", 747 | "datasource": "prometheus", 748 | "gridPos": { 749 | "h": 8, 750 | "w": 7, 751 | "x": 17, 752 | "y": 4 753 | }, 754 | "heatmap": {}, 755 | "hideZeroBuckets": false, 756 | "highlightCards": true, 757 | "id": 5, 758 | "legend": { 759 | "show": false 760 | }, 761 | "maxDataPoints": 50, 762 | "reverseYBuckets": false, 763 | "targets": [ 764 | { 765 | "exemplar": true, 766 | "expr": "sum(rate(apiserver_request_duration_seconds_bucket[$__rate_interval])) by (le)", 767 | "format": "heatmap", 768 | "interval": "", 769 | "legendFormat": "{{le}}", 770 | "queryType": "randomWalk", 771 | "refId": "A" 772 | } 773 | ], 774 | "title": "API Server Request Latency", 775 | "tooltip": { 776 | "show": true, 777 | "showHistogram": false 778 | }, 779 | "type": "heatmap", 780 | "xAxis": { 781 | "show": true 782 | }, 783 | "xBucketNumber": null, 784 | "xBucketSize": null, 785 | "yAxis": { 786 | "decimals": null, 787 | "format": "s", 788 | "logBase": 1, 789 | "max": null, 790 | "min": null, 791 | "show": true, 792 | "splitFactor": null 793 | }, 794 | "yBucketBound": "auto", 795 | "yBucketNumber": null, 796 | "yBucketSize": null 797 | }, 798 | { 799 | "datasource": "prometheus", 800 | "fieldConfig": { 801 | "defaults": { 802 | "color": { 803 | "mode": "palette-classic" 804 | }, 805 | "custom": { 806 | "axisLabel": "", 807 | "axisPlacement": "auto", 808 | "barAlignment": 0, 809 | "drawStyle": "line", 810 | "fillOpacity": 0, 811 | "gradientMode": "none", 812 | "hideFrom": { 813 | "legend": false, 814 | "tooltip": false, 815 | "viz": false 816 | }, 817 | "lineInterpolation": "linear", 818 | "lineWidth": 1, 819 | "pointSize": 5, 820 | "scaleDistribution": { 821 | "type": "linear" 822 | }, 823 | "showPoints": "auto", 824 | "spanNulls": false, 825 | "stacking": { 826 | "group": "A", 827 | "mode": "none" 828 | }, 829 | "thresholdsStyle": { 830 | "mode": "off" 831 | } 832 | }, 833 | "mappings": [], 834 | "thresholds": { 835 | "mode": "absolute", 836 | "steps": [ 837 | { 838 | "color": "green", 839 | "value": null 840 | }, 841 | { 842 | "color": "red", 843 | "value": 80 844 | } 845 | ] 846 | }, 847 | "unit": "dateTimeAsIso" 848 | }, 849 | "overrides": [] 850 | }, 851 | "gridPos": { 852 | "h": 4, 853 | "w": 11, 854 | "x": 0, 855 | "y": 12 856 | }, 857 | "id": 30, 858 | "options": { 859 | "legend": { 860 | "calcs": [], 861 | "displayMode": "list", 862 | "placement": "bottom" 863 | }, 864 | "tooltip": { 865 | "mode": "single" 866 | } 867 | }, 868 | "pluginVersion": "8.1.1", 869 | "targets": [ 870 | { 871 | "exemplar": true, 872 | "expr": "process_start_time_seconds{job=\"apiserver\"} * 1000", 873 | "interval": "", 874 | "legendFormat": "{{instance}}", 875 | "queryType": "randomWalk", 876 | "refId": "A" 877 | } 878 | ], 879 | "title": "API Server Started", 880 | "type": "timeseries" 881 | }, 882 | { 883 | "datasource": "prometheus", 884 | "fieldConfig": { 885 | "defaults": { 886 | "color": { 887 | "mode": "palette-classic" 888 | }, 889 | "custom": { 890 | "axisLabel": "", 891 | "axisPlacement": "auto", 892 | "axisSoftMin": 1, 893 | "barAlignment": 0, 894 | "drawStyle": "line", 895 | "fillOpacity": 6, 896 | "gradientMode": "none", 897 | "hideFrom": { 898 | "legend": false, 899 | "tooltip": false, 900 | "viz": false 901 | }, 902 | "lineInterpolation": "linear", 903 | "lineWidth": 1, 904 | "pointSize": 5, 905 | "scaleDistribution": { 906 | "type": "linear" 907 | }, 908 | "showPoints": "auto", 909 | "spanNulls": false, 910 | "stacking": { 911 | "group": "A", 912 | "mode": "normal" 913 | }, 914 | "thresholdsStyle": { 915 | "mode": "off" 916 | } 917 | }, 918 | "mappings": [], 919 | "thresholds": { 920 | "mode": "absolute", 921 | "steps": [ 922 | { 923 | "color": "green", 924 | "value": null 925 | }, 926 | { 927 | "color": "red", 928 | "value": 80 929 | } 930 | ] 931 | }, 932 | "unit": "s" 933 | }, 934 | "overrides": [] 935 | }, 936 | "gridPos": { 937 | "h": 6, 938 | "w": 13, 939 | "x": 11, 940 | "y": 12 941 | }, 942 | "id": 24, 943 | "options": { 944 | "legend": { 945 | "calcs": [], 946 | "displayMode": "list", 947 | "placement": "bottom" 948 | }, 949 | "tooltip": { 950 | "mode": "single" 951 | } 952 | }, 953 | "targets": [ 954 | { 955 | "exemplar": true, 956 | "expr": "sum by (instance) (rate(process_cpu_seconds_total{job=\"apiserver\"}[$__rate_interval]))", 957 | "interval": "", 958 | "legendFormat": "{{instance}}", 959 | "queryType": "randomWalk", 960 | "refId": "A" 961 | } 962 | ], 963 | "title": "API Server CPU", 964 | "type": "timeseries" 965 | }, 966 | { 967 | "datasource": "prometheus", 968 | "fieldConfig": { 969 | "defaults": { 970 | "color": { 971 | "mode": "palette-classic" 972 | }, 973 | "custom": { 974 | "axisLabel": "", 975 | "axisPlacement": "auto", 976 | "barAlignment": 0, 977 | "drawStyle": "line", 978 | "fillOpacity": 10, 979 | "gradientMode": "none", 980 | "hideFrom": { 981 | "legend": false, 982 | "tooltip": false, 983 | "viz": false 984 | }, 985 | "lineInterpolation": "linear", 986 | "lineWidth": 1, 987 | "pointSize": 5, 988 | "scaleDistribution": { 989 | "type": "linear" 990 | }, 991 | "showPoints": "auto", 992 | "spanNulls": false, 993 | "stacking": { 994 | "group": "A", 995 | "mode": "normal" 996 | }, 997 | "thresholdsStyle": { 998 | "mode": "off" 999 | } 1000 | }, 1001 | "mappings": [], 1002 | "thresholds": { 1003 | "mode": "absolute", 1004 | "steps": [ 1005 | { 1006 | "color": "green", 1007 | "value": null 1008 | }, 1009 | { 1010 | "color": "red", 1011 | "value": 80 1012 | } 1013 | ] 1014 | } 1015 | }, 1016 | "overrides": [] 1017 | }, 1018 | "gridPos": { 1019 | "h": 13, 1020 | "w": 11, 1021 | "x": 0, 1022 | "y": 16 1023 | }, 1024 | "id": 32, 1025 | "options": { 1026 | "legend": { 1027 | "calcs": [], 1028 | "displayMode": "list", 1029 | "placement": "bottom" 1030 | }, 1031 | "tooltip": { 1032 | "mode": "single" 1033 | } 1034 | }, 1035 | "targets": [ 1036 | { 1037 | "exemplar": true, 1038 | "expr": "count(count by (crd) (apiextensions_openapi_v2_regeneration_count{job=\"apiserver\", reason=\"add\"}))", 1039 | "interval": "", 1040 | "legendFormat": "CRDs", 1041 | "queryType": "randomWalk", 1042 | "refId": "A" 1043 | } 1044 | ], 1045 | "title": "API Server CRDs Added", 1046 | "type": "timeseries" 1047 | }, 1048 | { 1049 | "datasource": "prometheus", 1050 | "fieldConfig": { 1051 | "defaults": { 1052 | "color": { 1053 | "mode": "palette-classic" 1054 | }, 1055 | "custom": { 1056 | "axisLabel": "", 1057 | "axisPlacement": "auto", 1058 | "axisSoftMin": 0, 1059 | "barAlignment": 0, 1060 | "drawStyle": "line", 1061 | "fillOpacity": 14, 1062 | "gradientMode": "none", 1063 | "hideFrom": { 1064 | "legend": false, 1065 | "tooltip": false, 1066 | "viz": false 1067 | }, 1068 | "lineInterpolation": "linear", 1069 | "lineWidth": 1, 1070 | "pointSize": 5, 1071 | "scaleDistribution": { 1072 | "type": "linear" 1073 | }, 1074 | "showPoints": "auto", 1075 | "spanNulls": false, 1076 | "stacking": { 1077 | "group": "A", 1078 | "mode": "normal" 1079 | }, 1080 | "thresholdsStyle": { 1081 | "mode": "off" 1082 | } 1083 | }, 1084 | "mappings": [], 1085 | "thresholds": { 1086 | "mode": "absolute", 1087 | "steps": [ 1088 | { 1089 | "color": "green", 1090 | "value": null 1091 | }, 1092 | { 1093 | "color": "red", 1094 | "value": 80 1095 | } 1096 | ] 1097 | }, 1098 | "unit": "bytes" 1099 | }, 1100 | "overrides": [] 1101 | }, 1102 | "gridPos": { 1103 | "h": 5, 1104 | "w": 13, 1105 | "x": 11, 1106 | "y": 18 1107 | }, 1108 | "id": 26, 1109 | "options": { 1110 | "legend": { 1111 | "calcs": [], 1112 | "displayMode": "list", 1113 | "placement": "bottom" 1114 | }, 1115 | "tooltip": { 1116 | "mode": "single" 1117 | } 1118 | }, 1119 | "targets": [ 1120 | { 1121 | "exemplar": true, 1122 | "expr": "sum by (instance) (process_resident_memory_bytes{job=\"apiserver\"})", 1123 | "interval": "", 1124 | "legendFormat": "{{instance}}", 1125 | "queryType": "randomWalk", 1126 | "refId": "A" 1127 | } 1128 | ], 1129 | "title": "API Server Memory", 1130 | "type": "timeseries" 1131 | }, 1132 | { 1133 | "datasource": "prometheus", 1134 | "fieldConfig": { 1135 | "defaults": { 1136 | "color": { 1137 | "mode": "palette-classic" 1138 | }, 1139 | "custom": { 1140 | "axisLabel": "", 1141 | "axisPlacement": "auto", 1142 | "axisSoftMin": 0, 1143 | "barAlignment": 0, 1144 | "drawStyle": "line", 1145 | "fillOpacity": 10, 1146 | "gradientMode": "none", 1147 | "hideFrom": { 1148 | "legend": false, 1149 | "tooltip": false, 1150 | "viz": false 1151 | }, 1152 | "lineInterpolation": "linear", 1153 | "lineWidth": 1, 1154 | "pointSize": 5, 1155 | "scaleDistribution": { 1156 | "type": "linear" 1157 | }, 1158 | "showPoints": "auto", 1159 | "spanNulls": false, 1160 | "stacking": { 1161 | "group": "A", 1162 | "mode": "none" 1163 | }, 1164 | "thresholdsStyle": { 1165 | "mode": "off" 1166 | } 1167 | }, 1168 | "mappings": [], 1169 | "thresholds": { 1170 | "mode": "absolute", 1171 | "steps": [ 1172 | { 1173 | "color": "green", 1174 | "value": null 1175 | }, 1176 | { 1177 | "color": "red", 1178 | "value": 80 1179 | } 1180 | ] 1181 | } 1182 | }, 1183 | "overrides": [] 1184 | }, 1185 | "gridPos": { 1186 | "h": 6, 1187 | "w": 13, 1188 | "x": 11, 1189 | "y": 23 1190 | }, 1191 | "id": 34, 1192 | "options": { 1193 | "legend": { 1194 | "calcs": [], 1195 | "displayMode": "list", 1196 | "placement": "bottom" 1197 | }, 1198 | "tooltip": { 1199 | "mode": "single" 1200 | } 1201 | }, 1202 | "targets": [ 1203 | { 1204 | "exemplar": true, 1205 | "expr": "sum by (instance) (go_goroutines{job=\"apiserver\"})", 1206 | "interval": "", 1207 | "legendFormat": "{{instance}}", 1208 | "queryType": "randomWalk", 1209 | "refId": "A" 1210 | } 1211 | ], 1212 | "title": "API Server Goroutines", 1213 | "type": "timeseries" 1214 | } 1215 | ], 1216 | "refresh": "5s", 1217 | "schemaVersion": 30, 1218 | "style": "dark", 1219 | "tags": [], 1220 | "templating": { 1221 | "list": [] 1222 | }, 1223 | "time": { 1224 | "from": "now-30m", 1225 | "to": "now" 1226 | }, 1227 | "timepicker": {}, 1228 | "timezone": "", 1229 | "title": "Scale Testing", 1230 | "uid": "C_p1gHKnk", 1231 | "version": 3 1232 | } -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/monitoring/install-prometheus.md: -------------------------------------------------------------------------------- 1 | # Step 1: Clone the Prometheus operator repository and switch to the folder 2 | git clone https://github.com/prometheus-operator/kube-prometheus.git 3 | cd kube-prometheus 4 | # Step 2: Execute the initial setup instructions 5 | kubectl create -f manifests/setup 6 | # Step 3: Install the operator 7 | kubectl create -f manifests/ 8 | # Step 4: Once the pods are up and running, view the Prometheus dashboard after the port forward 9 | kubectl --namespace monitoring port-forward svc/Prometheus-k8s 9090 10 | 11 | http://localhost:9090/ -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/monitoring/monitor.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | namespace: crossplane-system 6 | name: prometheus-view 7 | subjects: 8 | - kind: ServiceAccount 9 | namespace: monitoring 10 | name: prometheus-k8s 11 | roleRef: 12 | kind: ClusterRole 13 | name: view 14 | apiGroup: rbac.authorization.k8s.io 15 | --- 16 | apiVersion: monitoring.coreos.com/v1 17 | kind: PodMonitor 18 | metadata: 19 | namespace: crossplane-system 20 | name: crossplane-providers 21 | spec: 22 | namespaceSelector: 23 | matchNames: 24 | - crossplane-system 25 | selector: 26 | matchExpressions: 27 | - key: crossplane.io/provider 28 | operator: Exists 29 | podMetricsEndpoints: 30 | - port: metrics 31 | --- 32 | apiVersion: monitoring.coreos.com/v1 33 | kind: PodMonitor 34 | metadata: 35 | namespace: crossplane-system 36 | name: crossplane 37 | spec: 38 | namespaceSelector: 39 | matchNames: 40 | - crossplane-system 41 | selector: 42 | matchExpressions: 43 | - key: app 44 | operator: In 45 | values: 46 | - crossplane 47 | podMetricsEndpoints: 48 | - port: metrics -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/same-nested-xr-reference/claim-bucket.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: reference.imarunrk.com/v1 2 | kind: MyBucket 3 | metadata: 4 | namespace: alpha 5 | name: my-bucket 6 | spec: 7 | compositionRef: 8 | name: my-bucket 9 | parameters: 10 | bucketName: test-reference-bucket-arun -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/same-nested-xr-reference/composition-IAM.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: resource-iam 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: reference.imarunrk.com/v1 8 | kind: XIAMResourceUser 9 | resources: 10 | # Create IAM user 11 | - base: 12 | apiVersion: iam.aws.crossplane.io/v1beta1 13 | kind: User 14 | spec: 15 | providerConfigRef: 16 | name: aws-credentials 17 | forProvider: 18 | path: "/" 19 | patches: 20 | # patch the name of IAM user with dynamic placeholder 21 | # user-- 22 | - type: CombineFromComposite 23 | toFieldPath: metadata.name 24 | combine: 25 | variables: 26 | - fromFieldPath: spec.parameters.resourceType 27 | - fromFieldPath: spec.parameters.resourceName 28 | strategy: string 29 | string: 30 | fmt: "user-%s-%s" 31 | # Attach the resource policy with the IAM User 32 | - base: 33 | apiVersion: iam.aws.crossplane.io/v1beta1 34 | kind: UserPolicyAttachment 35 | spec: 36 | providerConfigRef: 37 | name: aws-credentials 38 | forProvider: 39 | # refer to the IAM user from the same composition using matchControllerRef 40 | userNameSelector: 41 | matchControllerRef: true 42 | patches: 43 | # Patch the policy resource name with standerd name construction 44 | # -- 45 | - type: CombineFromComposite 46 | toFieldPath: metadata.name 47 | combine: 48 | variables: 49 | - fromFieldPath: spec.parameters.resourceType 50 | - fromFieldPath: spec.parameters.resourceName 51 | strategy: string 52 | string: 53 | fmt: "policy-attachement-%s-%s" 54 | # Patch the policy ARN reference 55 | - toFieldPath: spec.forProvider.policyArn 56 | fromFieldPath: spec.parameters.policyARN -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/same-nested-xr-reference/composition-bucket.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: my-bucket 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: reference.imarunrk.com/v1 8 | kind: XMyBucket 9 | resources: 10 | # Create the bucket resource 11 | - base: 12 | apiVersion: s3.aws.crossplane.io/v1beta1 13 | kind: Bucket 14 | spec: 15 | providerConfigRef: 16 | name: aws-credentials 17 | forProvider: 18 | acl: private 19 | locationConstraint: ap-south-1 20 | patches: 21 | # patch the name of the bucket 22 | - fromFieldPath: spec.parameters.bucketName 23 | toFieldPath: metadata.name 24 | # Define IAM policy resource for the bucket 25 | # Naming pattern: -- 26 | - base: 27 | apiVersion: iam.aws.crossplane.io/v1beta1 28 | kind: Policy 29 | spec: 30 | providerConfigRef: 31 | name: aws-credentials 32 | forProvider: 33 | path: "/" 34 | patches: 35 | # patch the MR name with the bucket name with prefix 36 | - fromFieldPath: spec.parameters.bucketName 37 | toFieldPath: metadata.name 38 | transforms: 39 | - type: string 40 | string: 41 | fmt: "policy-bucket-%s" 42 | # patch the policy name with the bucket name with prefix 43 | - fromFieldPath: spec.parameters.bucketName 44 | toFieldPath: spec.forProvider.name 45 | transforms: 46 | - type: string 47 | string: 48 | fmt: "policy-bucket-%s" 49 | # Patch the policy Json 50 | # Full access policy for specific S3 resource 51 | - type: CombineFromComposite 52 | toFieldPath: spec.forProvider.document 53 | combine: 54 | variables: 55 | - fromFieldPath: spec.parameters.bucketName 56 | - fromFieldPath: spec.parameters.bucketName 57 | strategy: string 58 | string: 59 | fmt: | 60 | { 61 | "Version": "2012-10-17", 62 | "Statement": [ 63 | { 64 | "Effect": "Allow", 65 | "Action": [ "s3:*" ], 66 | "Resource": [ 67 | "arn:aws:s3:::%s", 68 | "arn:aws:s3:::%s/*" 69 | ] 70 | } 71 | ] 72 | } 73 | # API response with policy ARN - used to feed the inner IAM XR 74 | - type: ToCompositeFieldPath 75 | fromFieldPath: status.atProvider.arn 76 | toFieldPath: status.policyARN 77 | # XR resource to create IAM resource and attach policy 78 | - base: 79 | apiVersion: reference.imarunrk.com/v1 80 | kind: XIAMResourceUser 81 | spec: 82 | compositionRef: 83 | name: resource-iam 84 | parameters: 85 | # Pass as input parameter 86 | # IAM XR will use this as a part of prefix 87 | resourceType: bucket 88 | patches: 89 | # patch the bucket name for the IAM user name prefix 90 | - fromFieldPath: spec.parameters.bucketName 91 | toFieldPath: spec.parameters.resourceName 92 | # patch the policy arn to attach the resource policy with IAM user 93 | - fromFieldPath: status.policyARN 94 | toFieldPath: spec.parameters.policyARN -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/same-nested-xr-reference/xrd-IAM.yaml: -------------------------------------------------------------------------------- 1 | # XRD for an XR API to create a IAM user with a specific resource access 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: xiamresourceusers.reference.imarunrk.com 6 | spec: 7 | group: reference.imarunrk.com 8 | names: 9 | kind: XIAMResourceUser 10 | plural: xiamresourceusers 11 | versions: 12 | - name: v1 13 | served: true 14 | referenceable: true 15 | schema: 16 | openAPIV3Schema: 17 | type: object 18 | properties: 19 | # Resource name, type and policy arn as API input 20 | spec: 21 | type: object 22 | properties: 23 | parameters: 24 | type: object 25 | properties: 26 | resourceName: 27 | description: The name that is used for IAM user creation. User the same name as resource name for resource policy lookup to work. 28 | type: string 29 | resourceType: 30 | description: A string used as a part of prefix in IAM creation. 31 | type: string 32 | policyARN: 33 | description: ARN of the resource policy. User as a attachement to the user. 34 | type: string 35 | required: 36 | - resourceName 37 | - resourceType 38 | - policyARN 39 | required: 40 | - parameters -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/same-nested-xr-reference/xrd-bucket.yaml: -------------------------------------------------------------------------------- 1 | # XRD for an API to create a bucket with and a IAM user for bucket access 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: xmybuckets.reference.imarunrk.com 6 | spec: 7 | group: reference.imarunrk.com 8 | names: 9 | kind: XMyBucket 10 | plural: xmybuckets 11 | claimNames: 12 | kind: MyBucket 13 | plural: mybuckets 14 | versions: 15 | - name: v1 16 | served: true 17 | referenceable: true 18 | schema: 19 | openAPIV3Schema: 20 | type: object 21 | properties: 22 | # S3 bucket name is the API input 23 | spec: 24 | type: object 25 | properties: 26 | parameters: 27 | type: object 28 | properties: 29 | bucketName: 30 | description: The name of the S3 bucket 31 | type: string 32 | required: 33 | - bucketName 34 | required: 35 | - parameters 36 | # policyARN is the API output, used to feed the inner IAM XR 37 | status: 38 | type: object 39 | properties: 40 | policyARN: 41 | description: Policy ARN to patch back to the IAM XR 42 | type: string -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/secret-propagation/claim-bucket.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: reference.imarunrk.com/v1 2 | kind: BucketWithCredential 3 | metadata: 4 | namespace: alpha 5 | name: iam-bucket 6 | spec: 7 | compositionRef: 8 | name: bucket-with-credentials 9 | parameters: 10 | bucketName: test-reference-bucket-arun -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/secret-propagation/composition-IAM.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: resource-iam-credentials 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: reference.imarunrk.com/v1 8 | kind: XIAMWithCredential 9 | resources: 10 | # Create IAM user 11 | - base: 12 | apiVersion: iam.aws.crossplane.io/v1beta1 13 | kind: User 14 | spec: 15 | providerConfigRef: 16 | name: aws-credentials 17 | forProvider: 18 | path: "/" 19 | patches: 20 | # patch the name of IAM user with dynamic placeholder 21 | # user-- 22 | - type: CombineFromComposite 23 | toFieldPath: metadata.name 24 | combine: 25 | variables: 26 | - fromFieldPath: spec.parameters.resourceType 27 | - fromFieldPath: spec.parameters.resourceName 28 | strategy: string 29 | string: 30 | fmt: "user-%s-%s" 31 | # Attach the resource policy with the IAM User 32 | - base: 33 | apiVersion: iam.aws.crossplane.io/v1beta1 34 | kind: UserPolicyAttachment 35 | spec: 36 | providerConfigRef: 37 | name: aws-credentials 38 | forProvider: 39 | # refer to the IAM user from the same composition using matchControllerRef 40 | userNameSelector: 41 | matchControllerRef: true 42 | patches: 43 | # Patch the policy resource name with standerd name construction 44 | # -- 45 | - type: CombineFromComposite 46 | toFieldPath: metadata.name 47 | combine: 48 | variables: 49 | - fromFieldPath: spec.parameters.resourceType 50 | - fromFieldPath: spec.parameters.resourceName 51 | strategy: string 52 | string: 53 | fmt: "policy-attachement-%s-%s" 54 | # Patch the policy ARN reference 55 | - toFieldPath: spec.forProvider.policyArn 56 | fromFieldPath: spec.parameters.policyARN 57 | - base: 58 | apiVersion: iam.aws.crossplane.io/v1beta1 59 | kind: AccessKey 60 | spec: 61 | providerConfigRef: 62 | name: aws-credentials 63 | forProvider: 64 | # refer to the IAM user from the same composition using matchControllerRef 65 | userNameSelector: 66 | matchControllerRef: true 67 | patches: 68 | # Patch the resource name with standerd name construction 69 | # -- 70 | - type: CombineFromComposite 71 | toFieldPath: metadata.name 72 | combine: 73 | variables: 74 | - fromFieldPath: spec.parameters.resourceType 75 | - fromFieldPath: spec.parameters.resourceName 76 | strategy: string 77 | string: 78 | fmt: "iam-access-%s-%s" 79 | # Namespace to save the secret same as the resource namespace 80 | - fromFieldPath: spec.parameters.secretNamespace 81 | toFieldPath: spec.writeConnectionSecretToRef.namespace 82 | # Generate and patch the kubernete secret name 83 | - type: CombineFromComposite 84 | toFieldPath: spec.writeConnectionSecretToRef.name 85 | combine: 86 | variables: 87 | - fromFieldPath: spec.parameters.resourceType 88 | - fromFieldPath: spec.parameters.resourceName 89 | strategy: string 90 | string: 91 | fmt: "credentials-%s-%s" 92 | # Populate the connection secret keys from AccessKey secrets 93 | connectionDetails: 94 | - name: iam_username 95 | fromConnectionSecretKey: username 96 | - name: iam_password 97 | fromConnectionSecretKey: password -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/secret-propagation/composition-bucket.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: bucket-with-credentials 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: reference.imarunrk.com/v1 8 | kind: XBucketWithCredential 9 | resources: 10 | # Create the bucket resource 11 | - base: 12 | apiVersion: s3.aws.crossplane.io/v1beta1 13 | kind: Bucket 14 | spec: 15 | providerConfigRef: 16 | name: aws-credentials 17 | forProvider: 18 | acl: private 19 | locationConstraint: ap-south-1 20 | patches: 21 | # patch the name of the bucket 22 | - fromFieldPath: spec.parameters.bucketName 23 | toFieldPath: metadata.name 24 | # Namespace to save the secret same as the resource namespace 25 | - fromFieldPath: spec.claimRef.namespace 26 | toFieldPath: spec.writeConnectionSecretToRef.namespace 27 | # Generate and patch the kubernete secret name 28 | - fromFieldPath: spec.parameters.bucketName 29 | toFieldPath: spec.writeConnectionSecretToRef.name 30 | transforms: 31 | - type: string 32 | string: 33 | fmt: "details-bucket-%s" 34 | # copy the endpoint from the connection secret key to bucketURL 35 | connectionDetails: 36 | - name: bucketURL 37 | fromConnectionSecretKey: endpoint 38 | # Define IAM policy resource for the bucket 39 | # Naming pattern: -- 40 | - base: 41 | apiVersion: iam.aws.crossplane.io/v1beta1 42 | kind: Policy 43 | spec: 44 | providerConfigRef: 45 | name: aws-credentials 46 | forProvider: 47 | path: "/" 48 | patches: 49 | # patch the MR name with the bucket name with prefix 50 | - fromFieldPath: spec.parameters.bucketName 51 | toFieldPath: metadata.name 52 | transforms: 53 | - type: string 54 | string: 55 | fmt: "policy-bucket-%s" 56 | # patch the policy name with the bucket name with prefix 57 | - fromFieldPath: spec.parameters.bucketName 58 | toFieldPath: spec.forProvider.name 59 | transforms: 60 | - type: string 61 | string: 62 | fmt: "policy-bucket-%s" 63 | # Patch the policy Json 64 | # Full access policy for specific S3 resource 65 | - type: CombineFromComposite 66 | toFieldPath: spec.forProvider.document 67 | combine: 68 | variables: 69 | - fromFieldPath: spec.parameters.bucketName 70 | - fromFieldPath: spec.parameters.bucketName 71 | strategy: string 72 | string: 73 | fmt: | 74 | { 75 | "Version": "2012-10-17", 76 | "Statement": [ 77 | { 78 | "Effect": "Allow", 79 | "Action": [ "s3:*" ], 80 | "Resource": [ 81 | "arn:aws:s3:::%s", 82 | "arn:aws:s3:::%s/*" 83 | ] 84 | } 85 | ] 86 | } 87 | # API response with policy ARN - used to feed the inner IAM XR 88 | - type: ToCompositeFieldPath 89 | fromFieldPath: status.atProvider.arn 90 | toFieldPath: status.policyARN 91 | # XR resource to create IAM resource and attach policy 92 | - base: 93 | apiVersion: reference.imarunrk.com/v1 94 | kind: XIAMWithCredential 95 | spec: 96 | compositionRef: 97 | name: resource-iam-credentials 98 | parameters: 99 | # Pass as input parameter 100 | # IAM XR will use this as a part of prefix 101 | resourceType: bucket 102 | patches: 103 | # patch the bucket name for the IAM user name prefix 104 | - fromFieldPath: spec.parameters.bucketName 105 | toFieldPath: spec.parameters.resourceName 106 | # patch the policy arn to attach the resource policy with IAM user 107 | - fromFieldPath: status.policyARN 108 | toFieldPath: spec.parameters.policyARN 109 | # Namespace to save the secret. Same as the resource namespace 110 | - fromFieldPath: spec.claimRef.namespace 111 | toFieldPath: spec.parameters.secretNamespace -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/secret-propagation/xrd-IAM.yaml: -------------------------------------------------------------------------------- 1 | # XRD for an XR API to create a IAM user with a specific resource access 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: xiamwithcredentials.reference.imarunrk.com 6 | spec: 7 | group: reference.imarunrk.com 8 | names: 9 | kind: XIAMWithCredential 10 | plural: xiamwithcredentials 11 | connectionSecretKeys: 12 | - iam_username 13 | - iam_password 14 | versions: 15 | - name: v1 16 | served: true 17 | referenceable: true 18 | schema: 19 | openAPIV3Schema: 20 | type: object 21 | properties: 22 | # Resource name, type and policy arn as API input 23 | spec: 24 | type: object 25 | properties: 26 | parameters: 27 | type: object 28 | properties: 29 | resourceName: 30 | description: The name that is used for IAM user creation. User the same name as resource name for resource policy lookup to work. 31 | type: string 32 | resourceType: 33 | description: A string used as a part of prefix in IAM creation. 34 | type: string 35 | policyARN: 36 | description: ARN of the resource policy. User as a attachement to the user. 37 | type: string 38 | secretNamespace: 39 | description: namespace to store the secret 40 | type: string 41 | required: 42 | - resourceName 43 | - resourceType 44 | - policyARN 45 | - secretNamespace 46 | required: 47 | - parameters -------------------------------------------------------------------------------- /Chapter06/Hand-on-examples/secret-propagation/xrd-bucket.yaml: -------------------------------------------------------------------------------- 1 | # XRD for an API to create a bucket with and a IAM user for bucket access 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: xbucketwithcredentials.reference.imarunrk.com 6 | spec: 7 | group: reference.imarunrk.com 8 | names: 9 | kind: XBucketWithCredential 10 | plural: xbucketwithcredentials 11 | claimNames: 12 | kind: BucketWithCredential 13 | plural: bucketwithcredentials 14 | connectionSecretKeys: 15 | - bucket_url 16 | versions: 17 | - name: v1 18 | served: true 19 | referenceable: true 20 | schema: 21 | openAPIV3Schema: 22 | type: object 23 | properties: 24 | # S3 bucket name is the API input 25 | spec: 26 | type: object 27 | properties: 28 | parameters: 29 | type: object 30 | properties: 31 | bucketName: 32 | description: The name of the S3 bucket 33 | type: string 34 | required: 35 | - bucketName 36 | required: 37 | - parameters 38 | # policyARN is the API output, used to feed the inner IAM XR 39 | status: 40 | type: object 41 | properties: 42 | policyARN: 43 | description: Policy ARN to patch back to the IAM XR 44 | type: string -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/configuration/Bucket/composition-bucket.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: bucket-with-credentials 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: reference.imarunrk.com/v1 8 | kind: XBucketWithCredential 9 | resources: 10 | # Create the bucket resource 11 | - base: 12 | apiVersion: s3.aws.crossplane.io/v1beta1 13 | kind: Bucket 14 | spec: 15 | providerConfigRef: 16 | name: aws-credentials 17 | forProvider: 18 | acl: private 19 | locationConstraint: ap-south-1 20 | tagging: 21 | tagSet: 22 | - key: ConfigurationVersion 23 | value: 1.1.0 24 | patches: 25 | # patch the name of the bucket 26 | - fromFieldPath: spec.parameters.bucketName 27 | toFieldPath: metadata.name 28 | # Namespace to save the secret same as the resource namespace 29 | - fromFieldPath: spec.claimRef.namespace 30 | toFieldPath: spec.writeConnectionSecretToRef.namespace 31 | # Generate and patch the kubernete secret name 32 | - fromFieldPath: spec.parameters.bucketName 33 | toFieldPath: spec.writeConnectionSecretToRef.name 34 | transforms: 35 | - type: string 36 | string: 37 | fmt: "details-bucket-%s" 38 | # copy the endpoint from the connection secret key to bucketURL 39 | connectionDetails: 40 | - name: bucketURL 41 | fromConnectionSecretKey: endpoint 42 | # Define IAM policy resource for the bucket 43 | # Naming pattern: -- 44 | - base: 45 | apiVersion: iam.aws.crossplane.io/v1beta1 46 | kind: Policy 47 | spec: 48 | providerConfigRef: 49 | name: aws-credentials 50 | forProvider: 51 | path: "/" 52 | patches: 53 | # patch the MR name with the bucket name with prefix 54 | - fromFieldPath: spec.parameters.bucketName 55 | toFieldPath: metadata.name 56 | transforms: 57 | - type: string 58 | string: 59 | fmt: "policy-bucket-%s" 60 | # patch the policy name with the bucket name with prefix 61 | - fromFieldPath: spec.parameters.bucketName 62 | toFieldPath: spec.forProvider.name 63 | transforms: 64 | - type: string 65 | string: 66 | fmt: "policy-bucket-%s" 67 | # Patch the policy Json 68 | # Full access policy for specific S3 resource 69 | - type: CombineFromComposite 70 | toFieldPath: spec.forProvider.document 71 | combine: 72 | variables: 73 | - fromFieldPath: spec.parameters.bucketName 74 | - fromFieldPath: spec.parameters.bucketName 75 | strategy: string 76 | string: 77 | fmt: | 78 | { 79 | "Version": "2012-10-17", 80 | "Statement": [ 81 | { 82 | "Effect": "Allow", 83 | "Action": [ "s3:*" ], 84 | "Resource": [ 85 | "arn:aws:s3:::%s", 86 | "arn:aws:s3:::%s/*" 87 | ] 88 | } 89 | ] 90 | } 91 | # API response with policy ARN - used to feed the inner IAM XR 92 | - type: ToCompositeFieldPath 93 | fromFieldPath: status.atProvider.arn 94 | toFieldPath: status.policyARN 95 | # XR resource to create IAM resource and attach policy 96 | - base: 97 | apiVersion: reference.imarunrk.com/v1 98 | kind: XIAMWithCredential 99 | spec: 100 | compositionRef: 101 | name: resource-iam-credentials 102 | parameters: 103 | # Pass as input parameter 104 | # IAM XR will use this as a part of prefix 105 | resourceType: bucket 106 | patches: 107 | # patch the bucket name for the IAM user name prefix 108 | - fromFieldPath: spec.parameters.bucketName 109 | toFieldPath: spec.parameters.resourceName 110 | # patch the policy arn to attach the resource policy with IAM user 111 | - fromFieldPath: status.policyARN 112 | toFieldPath: spec.parameters.policyARN 113 | # Namespace to save the secret. Same as the resource namespace 114 | - fromFieldPath: spec.claimRef.namespace 115 | toFieldPath: spec.parameters.secretNamespace -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/configuration/Bucket/xrd-bucket.yaml: -------------------------------------------------------------------------------- 1 | # XRD for an API to create a bucket with and a IAM user for bucket access 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: xbucketwithcredentials.reference.imarunrk.com 6 | spec: 7 | group: reference.imarunrk.com 8 | names: 9 | kind: XBucketWithCredential 10 | plural: xbucketwithcredentials 11 | claimNames: 12 | kind: BucketWithCredential 13 | plural: bucketwithcredentials 14 | connectionSecretKeys: 15 | - bucket_url 16 | versions: 17 | - name: v1 18 | served: true 19 | referenceable: true 20 | schema: 21 | openAPIV3Schema: 22 | type: object 23 | properties: 24 | # S3 bucket name is the API input 25 | spec: 26 | type: object 27 | properties: 28 | parameters: 29 | type: object 30 | properties: 31 | bucketName: 32 | description: The name of the S3 bucket 33 | type: string 34 | required: 35 | - bucketName 36 | required: 37 | - parameters 38 | # policyARN is the API output, used to feed the inner IAM XR 39 | status: 40 | type: object 41 | properties: 42 | policyARN: 43 | description: Policy ARN to patch back to the IAM XR 44 | type: string -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/configuration/IAM/composition-IAM.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: resource-iam-credentials 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: reference.imarunrk.com/v1 8 | kind: XIAMWithCredential 9 | resources: 10 | # Create IAM user 11 | - base: 12 | apiVersion: iam.aws.crossplane.io/v1beta1 13 | kind: User 14 | spec: 15 | providerConfigRef: 16 | name: aws-credentials 17 | forProvider: 18 | path: "/" 19 | patches: 20 | # patch the name of IAM user with dynamic placeholder 21 | # user-- 22 | - type: CombineFromComposite 23 | toFieldPath: metadata.name 24 | combine: 25 | variables: 26 | - fromFieldPath: spec.parameters.resourceType 27 | - fromFieldPath: spec.parameters.resourceName 28 | strategy: string 29 | string: 30 | fmt: "user-%s-%s" 31 | # Attach the resource policy with the IAM User 32 | - base: 33 | apiVersion: iam.aws.crossplane.io/v1beta1 34 | kind: UserPolicyAttachment 35 | spec: 36 | providerConfigRef: 37 | name: aws-credentials 38 | forProvider: 39 | # refer to the IAM user from the same composition using matchControllerRef 40 | userNameSelector: 41 | matchControllerRef: true 42 | patches: 43 | # Patch the policy resource name with standerd name construction 44 | # -- 45 | - type: CombineFromComposite 46 | toFieldPath: metadata.name 47 | combine: 48 | variables: 49 | - fromFieldPath: spec.parameters.resourceType 50 | - fromFieldPath: spec.parameters.resourceName 51 | strategy: string 52 | string: 53 | fmt: "policy-attachement-%s-%s" 54 | # Patch the policy ARN reference 55 | - toFieldPath: spec.forProvider.policyArn 56 | fromFieldPath: spec.parameters.policyARN 57 | - base: 58 | apiVersion: iam.aws.crossplane.io/v1beta1 59 | kind: AccessKey 60 | spec: 61 | providerConfigRef: 62 | name: aws-credentials 63 | forProvider: 64 | # refer to the IAM user from the same composition using matchControllerRef 65 | userNameSelector: 66 | matchControllerRef: true 67 | patches: 68 | # Patch the resource name with standerd name construction 69 | # -- 70 | - type: CombineFromComposite 71 | toFieldPath: metadata.name 72 | combine: 73 | variables: 74 | - fromFieldPath: spec.parameters.resourceType 75 | - fromFieldPath: spec.parameters.resourceName 76 | strategy: string 77 | string: 78 | fmt: "iam-access-%s-%s" 79 | # Namespace to save the secret same as the resource namespace 80 | - fromFieldPath: spec.parameters.secretNamespace 81 | toFieldPath: spec.writeConnectionSecretToRef.namespace 82 | # Generate and patch the kubernete secret name 83 | - type: CombineFromComposite 84 | toFieldPath: spec.writeConnectionSecretToRef.name 85 | combine: 86 | variables: 87 | - fromFieldPath: spec.parameters.resourceType 88 | - fromFieldPath: spec.parameters.resourceName 89 | strategy: string 90 | string: 91 | fmt: "credentials-%s-%s" 92 | # Populate the connection secret keys from AccessKey secrets 93 | connectionDetails: 94 | - name: iam_username 95 | fromConnectionSecretKey: username 96 | - name: iam_password 97 | fromConnectionSecretKey: password -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/configuration/IAM/xrd-IAM.yaml: -------------------------------------------------------------------------------- 1 | # XRD for an XR API to create a IAM user with a specific resource access 2 | apiVersion: apiextensions.crossplane.io/v1 3 | kind: CompositeResourceDefinition 4 | metadata: 5 | name: xiamwithcredentials.reference.imarunrk.com 6 | spec: 7 | group: reference.imarunrk.com 8 | names: 9 | kind: XIAMWithCredential 10 | plural: xiamwithcredentials 11 | connectionSecretKeys: 12 | - iam_username 13 | - iam_password 14 | versions: 15 | - name: v1 16 | served: true 17 | referenceable: true 18 | schema: 19 | openAPIV3Schema: 20 | type: object 21 | properties: 22 | # Resource name, type and policy arn as API input 23 | spec: 24 | type: object 25 | properties: 26 | parameters: 27 | type: object 28 | properties: 29 | resourceName: 30 | description: The name that is used for IAM user creation. User the same name as resource name for resource policy lookup to work. 31 | type: string 32 | resourceType: 33 | description: A string used as a part of prefix in IAM creation. 34 | type: string 35 | policyARN: 36 | description: ARN of the resource policy. User as a attachement to the user. 37 | type: string 38 | secretNamespace: 39 | description: namespace to store the secret 40 | type: string 41 | required: 42 | - resourceName 43 | - resourceType 44 | - policyARN 45 | - secretNamespace 46 | required: 47 | - parameters -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/configuration/crossplane.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: meta.pkg.crossplane.io/v1 2 | kind: Configuration 3 | metadata: 4 | name: aws-bucket 5 | spec: 6 | crossplane: 7 | version: ">=v1.6.0" 8 | dependsOn: 9 | - provider: crossplane/provider-aws 10 | version: ">=v0.23.0" -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/test-configuration/bucketwithcredential/bucket-failure/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | timeout: 20 4 | --- 5 | apiVersion: s3.aws.crossplane.io/v1beta1 6 | kind: Bucket 7 | metadata: 8 | name: bucket-arun1 -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/test-configuration/bucketwithcredential/bucket-failure/00-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: reference.imarunrk.com/v1 2 | kind: BucketWithCredential 3 | metadata: 4 | name: iam-bucket 5 | spec: 6 | compositionRef: 7 | name: bucket-with-credentials 8 | parameters: 9 | bucketName: test-reference -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/test-configuration/bucketwithcredential/bucket-success/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | timeout: 20 4 | --- 5 | apiVersion: s3.aws.crossplane.io/v1beta1 6 | kind: Bucket 7 | metadata: 8 | name: test-reference-bucket-arun -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/test-configuration/bucketwithcredential/bucket-success/00-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: reference.imarunrk.com/v1 2 | kind: BucketWithCredential 3 | metadata: 4 | name: iam-bucket 5 | spec: 6 | compositionRef: 7 | name: bucket-with-credentials 8 | parameters: 9 | bucketName: test-reference-bucket-arun -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/test-configuration/init/provider-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: aws-creds 6 | namespace: crossplane-system 7 | type: Opaque 8 | stringData: 9 | key: nocreds 10 | --- 11 | apiVersion: aws.crossplane.io/v1beta1 12 | kind: ProviderConfig 13 | metadata: 14 | name: default 15 | spec: 16 | credentials: 17 | source: Secret 18 | secretRef: 19 | namespace: crossplane-system 20 | name: aws-creds 21 | key: key -------------------------------------------------------------------------------- /Chapter07/Hand-on-examples/test-configuration/kuttl-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestSuite 3 | # Information on k8s cluster to use for testing 4 | startKIND: false 5 | kindContext: gke_crossplane-339717_us-central1_autopilot-cluster-1 6 | skipClusterDelete: true 7 | # Commands to be executed for any initial setup before testing 8 | commands: 9 | - command: kubectl apply -f init/ 10 | # Directory where all our tests are kept 11 | testDirs: 12 | - ./bucketwithcredential -------------------------------------------------------------------------------- /Chapter07/Samples/configuration.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Configuration 3 | metadata: 4 | name: aws-bucket 5 | spec: 6 | package: arunramakani/aws-bucket:v0.7.0 7 | packagePullPolicy: IfNotPresent 8 | revisionActivationPolicy: Manual 9 | revisionHistoryLimit: 3 -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/KubeVela/application.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: core.oam.dev/v1beta1 2 | kind: Application 3 | metadata: 4 | name: my-first-app 5 | spec: 6 | components: 7 | - name: helloworld 8 | type: webservice 9 | properties: 10 | image: oamdev/helloworld-python:v1 11 | env: 12 | - name: "TARGET" 13 | value: "KubeVela" 14 | port: 8080 15 | traits: 16 | - type: ingress 17 | properties: 18 | domain: localhost 19 | http: 20 | /: 8080 21 | policies: 22 | - name: keep-legacy-resource 23 | type: garbage-collect 24 | properties: 25 | keepLegacyResource: true 26 | workflow: 27 | steps: 28 | - name: simple-workflow 29 | type: apply-application -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: hello-world 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "1.16.0" 25 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "hello-world.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "hello-world.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "hello-world.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "hello-world.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "hello-world.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "hello-world.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "hello-world.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "hello-world.labels" -}} 37 | helm.sh/chart: {{ include "hello-world.chart" . }} 38 | {{ include "hello-world.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "hello-world.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "hello-world.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "hello-world.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "hello-world.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "hello-world.fullname" . }} 5 | labels: 6 | {{- include "hello-world.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "hello-world.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | labels: 21 | {{- include "hello-world.selectorLabels" . | nindent 8 }} 22 | spec: 23 | {{- with .Values.imagePullSecrets }} 24 | imagePullSecrets: 25 | {{- toYaml . | nindent 8 }} 26 | {{- end }} 27 | serviceAccountName: {{ include "hello-world.serviceAccountName" . }} 28 | securityContext: 29 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 30 | containers: 31 | - name: {{ .Chart.Name }} 32 | securityContext: 33 | {{- toYaml .Values.securityContext | nindent 12 }} 34 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 35 | imagePullPolicy: {{ .Values.image.pullPolicy }} 36 | ports: 37 | - name: http 38 | containerPort: 80 39 | protocol: TCP 40 | livenessProbe: 41 | httpGet: 42 | path: / 43 | port: http 44 | readinessProbe: 45 | httpGet: 46 | path: / 47 | port: http 48 | resources: 49 | {{- toYaml .Values.resources | nindent 12 }} 50 | {{- with .Values.nodeSelector }} 51 | nodeSelector: 52 | {{- toYaml . | nindent 8 }} 53 | {{- end }} 54 | {{- with .Values.affinity }} 55 | affinity: 56 | {{- toYaml . | nindent 8 }} 57 | {{- end }} 58 | {{- with .Values.tolerations }} 59 | tolerations: 60 | {{- toYaml . | nindent 8 }} 61 | {{- end }} 62 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "hello-world.fullname" . }} 6 | labels: 7 | {{- include "hello-world.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "hello-world.fullname" . }} 13 | minReplicas: {{ .Values.autoscaling.minReplicas }} 14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 15 | metrics: 16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 17 | - type: Resource 18 | resource: 19 | name: cpu 20 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 21 | {{- end }} 22 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 23 | - type: Resource 24 | resource: 25 | name: memory 26 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 27 | {{- end }} 28 | {{- end }} 29 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "hello-world.fullname" . -}} 3 | {{- $svcPort := .Values.service.port -}} 4 | {{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} 5 | {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} 6 | {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} 7 | {{- end }} 8 | {{- end }} 9 | {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} 10 | apiVersion: networking.k8s.io/v1 11 | {{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 12 | apiVersion: networking.k8s.io/v1beta1 13 | {{- else -}} 14 | apiVersion: extensions/v1beta1 15 | {{- end }} 16 | kind: Ingress 17 | metadata: 18 | name: {{ $fullName }} 19 | labels: 20 | {{- include "hello-world.labels" . | nindent 4 }} 21 | {{- with .Values.ingress.annotations }} 22 | annotations: 23 | {{- toYaml . | nindent 4 }} 24 | {{- end }} 25 | spec: 26 | {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} 27 | ingressClassName: {{ .Values.ingress.className }} 28 | {{- end }} 29 | {{- if .Values.ingress.tls }} 30 | tls: 31 | {{- range .Values.ingress.tls }} 32 | - hosts: 33 | {{- range .hosts }} 34 | - {{ . | quote }} 35 | {{- end }} 36 | secretName: {{ .secretName }} 37 | {{- end }} 38 | {{- end }} 39 | rules: 40 | {{- range .Values.ingress.hosts }} 41 | - host: {{ .host | quote }} 42 | http: 43 | paths: 44 | {{- range .paths }} 45 | - path: {{ .path }} 46 | {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} 47 | pathType: {{ .pathType }} 48 | {{- end }} 49 | backend: 50 | {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} 51 | service: 52 | name: {{ $fullName }} 53 | port: 54 | number: {{ $svcPort }} 55 | {{- else }} 56 | serviceName: {{ $fullName }} 57 | servicePort: {{ $svcPort }} 58 | {{- end }} 59 | {{- end }} 60 | {{- end }} 61 | {{- end }} 62 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "hello-world.fullname" . }} 5 | labels: 6 | {{- include "hello-world.labels" . | nindent 4 }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.port }} 11 | targetPort: http 12 | protocol: TCP 13 | name: http 14 | selector: 15 | {{- include "hello-world.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "hello-world.serviceAccountName" . }} 6 | labels: 7 | {{- include "hello-world.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "hello-world.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "hello-world.labels" . | nindent 4 }} 7 | annotations: 8 | "helm.sh/hook": test 9 | spec: 10 | containers: 11 | - name: wget 12 | image: busybox 13 | command: ['wget'] 14 | args: ['{{ include "hello-world.fullname" . }}:{{ .Values.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/helm/hello-world/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for hello-world. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: hello-world 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: {} 29 | # fsGroup: 2000 30 | 31 | securityContext: {} 32 | # capabilities: 33 | # drop: 34 | # - ALL 35 | # readOnlyRootFilesystem: true 36 | # runAsNonRoot: true 37 | # runAsUser: 1000 38 | 39 | service: 40 | type: ClusterIP 41 | port: 80 42 | 43 | ingress: 44 | enabled: false 45 | className: "" 46 | annotations: {} 47 | # kubernetes.io/ingress.class: nginx 48 | # kubernetes.io/tls-acme: "true" 49 | hosts: 50 | - host: chart-example.local 51 | paths: 52 | - path: / 53 | pathType: ImplementationSpecific 54 | tls: [] 55 | # - secretName: chart-example-tls 56 | # hosts: 57 | # - chart-example.local 58 | 59 | resources: {} 60 | # We usually recommend not to specify default resources and to leave this as a conscious 61 | # choice for the user. This also increases chances charts run on environments with little 62 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 63 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 64 | # limits: 65 | # cpu: 100m 66 | # memory: 128Mi 67 | # requests: 68 | # cpu: 100m 69 | # memory: 128Mi 70 | 71 | autoscaling: 72 | enabled: false 73 | minReplicas: 1 74 | maxReplicas: 100 75 | targetCPUUtilizationPercentage: 80 76 | # targetMemoryUtilizationPercentage: 80 77 | 78 | nodeSelector: {} 79 | 80 | tolerations: [] 81 | 82 | affinity: {} 83 | -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/kustomize/example1/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: busybox-deployment 5 | labels: 6 | app: busybox 7 | spec: 8 | replicas: 1 9 | strategy: 10 | type: RollingUpdate 11 | selector: 12 | matchLabels: 13 | app: busybox 14 | template: 15 | metadata: 16 | labels: 17 | app: busybox 18 | spec: 19 | containers: 20 | - name: busybox 21 | image: busybox 22 | imagePullPolicy: IfNotPresent 23 | command: ['sh', '-c', 'echo Container 1 is Running ; sleep 3600'] -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/kustomize/example1/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - deployment.yaml 3 | commonLabels: 4 | team-name: alpha 5 | namespace: test -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/kustomize/example2/composition.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: xclouddb-composition 5 | spec: 6 | # Link Composition to a specific XR and version 7 | compositeTypeRef: 8 | apiVersion: xclouddb.book.imarunrk.com/v1 9 | kind: Xclouddb 10 | # Connection secrets namespace 11 | writeConnectionSecretsToNamespace: crossplane-system 12 | # List of composed MRs or XRs. 13 | resources: 14 | - name: clouddbInstance 15 | # Resource base template 16 | base: 17 | apiVersion: database.gcp.crossplane.io/v1beta1 18 | kind: CloudSQLInstance 19 | spec: 20 | forProvider: 21 | databaseVersion: POSTGRES_9_6 22 | region: us-central 23 | settings: 24 | tier: db-g1-small 25 | dataDiskSizeGb: 20 26 | # Resource patches 27 | patches: 28 | - type: FromCompositeFieldPath 29 | fromFieldPath: spec.parameters.storageSize 30 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 31 | # Resource secrets 32 | connectionDetails: 33 | - name: hostname 34 | fromConnectionSecretKey: hostname -------------------------------------------------------------------------------- /Chapter09/Hand-on-examples/kustomize/example2/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - composition.yaml 3 | commonLabels: 4 | team-name: alpha -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-1-ProviderSetup/Platform-OPS/Additional-Steps.md: -------------------------------------------------------------------------------- 1 | # Create kubernetes secret from with the gitlab access token 2 | kubectl create secret generic gitlab-credentials -n crossplane-system --from-literal=gitlab-credentials="" 3 | 4 | # We can create the gitlab token from the Gitlab web UI or CLI 5 | 6 | # Only install the provider YAML for Helm and k8s Crossplane Provider. The ProviderConfig will be created automatically for the remote cluster in the next step when the k8s cluster is created. -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-1-ProviderSetup/Platform-OPS/GCP/GCP-Provider.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: provider-gcp 5 | spec: 6 | package: crossplane/provider-gcp:v0.18.0 -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-1-ProviderSetup/Platform-OPS/GCP/product-a/Provider-Config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: gcp.crossplane.io/v1beta1 2 | kind: ProviderConfig 3 | metadata: 4 | name: product-a 5 | spec: 6 | projectID: crossplane-339717 7 | credentials: 8 | source: Secret 9 | secretRef: 10 | namespace: crossplane-system 11 | name: gcp-account 12 | key: service-account -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-1-ProviderSetup/Platform-OPS/GCP/product-a/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: product-a 5 | labels: 6 | name: product-a -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-1-ProviderSetup/Platform-OPS/Gitlab/product-a/provider-config.yaml: -------------------------------------------------------------------------------- 1 | # Gitlab provider that references the secret credentials 2 | apiVersion: gitlab.crossplane.io/v1beta1 3 | kind: ProviderConfig 4 | metadata: 5 | name: product-a 6 | spec: 7 | baseURL: https://gitlab.com/ 8 | credentials: 9 | source: Secret 10 | secretRef: 11 | namespace: crossplane-system 12 | name: gitlab-credentials 13 | key: gitlab-credentials -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-1-ProviderSetup/Platform-OPS/Gitlab/provider-gitlab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: provider-gitlab 5 | spec: 6 | package: crossplane/provider-gitlab:v0.2.0 -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-1-ProviderSetup/Platform-OPS/Helm/Helm-Provider.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: provider-helm 5 | spec: 6 | package: crossplane/provider-helm:master -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-1-ProviderSetup/Platform-OPS/k8s/k8s-Provider.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: pkg.crossplane.io/v1 2 | kind: Provider 3 | metadata: 4 | name: provider-kubernetes 5 | spec: 6 | package: "crossplane/provider-kubernetes:main" -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-2-CreateProductTeamsKubernetesCluster/Application-OPS/cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: learn.unified.devops/v1alpha1 2 | kind: GCPCluster 3 | metadata: 4 | name: product-a-cluster 5 | namespace: product-a 6 | spec: 7 | compositionRef: 8 | name: xcluster-dev 9 | parameters: 10 | nodeCount: 5 11 | size: BIG -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-2-CreateProductTeamsKubernetesCluster/Platform-OPS/cluster-composition.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: xcluster-dev 5 | spec: 6 | writeConnectionSecretsToNamespace: crossplane-system 7 | compositeTypeRef: 8 | apiVersion: learn.unified.devops/v1alpha1 9 | kind: XGCPCluster 10 | resources: 11 | - name: gke-dev-cluster 12 | base: 13 | apiVersion: container.gcp.crossplane.io/v1beta2 14 | kind: Cluster 15 | spec: 16 | forProvider: 17 | location: us-west2 18 | loggingService: logging.googleapis.com/kubernetes 19 | monitoringService: monitoring.googleapis.com/kubernetes 20 | patches: 21 | - fromFieldPath: spec.claimRef.namespace 22 | toFieldPath: spec.providerConfigRef.name 23 | - fromFieldPath: spec.claimRef.name 24 | toFieldPath: metadata.name 25 | - fromFieldPath: spec.claimRef.namespace 26 | toFieldPath: spec.writeConnectionSecretToRef.namespace 27 | - fromFieldPath: spec.claimRef.name 28 | toFieldPath: spec.writeConnectionSecretToRef.name 29 | transforms: 30 | - type: string 31 | string: 32 | fmt: "%s-secret" 33 | - name: gke-dev-cluster-nodepool 34 | base: 35 | apiVersion: container.gcp.crossplane.io/v1beta1 36 | kind: NodePool 37 | spec: 38 | forProvider: 39 | autoscaling: 40 | autoprovisioned: false 41 | enabled: true 42 | minNodeCount: 4 43 | config: 44 | machineType: e2-medium 45 | initialNodeCount: 4 46 | locations: 47 | - "us-west2-a" 48 | patches: 49 | - fromFieldPath: spec.claimRef.namespace 50 | toFieldPath: spec.providerConfigRef.name 51 | - fromFieldPath: spec.claimRef.name 52 | toFieldPath: spec.forProvider.clusterRef.name 53 | - fromFieldPath: spec.parameters.nodeCount 54 | toFieldPath: spec.forProvider.autoscaling.maxNodeCount 55 | - type: FromCompositeFieldPath 56 | fromFieldPath: spec.parameters.size 57 | toFieldPath: spec.forProvider.config.machineType 58 | transforms: 59 | - type: map 60 | map: 61 | BIG: e2-medium 62 | SMALL: e2-small 63 | - name: gke-dev-cluster-helm-provider-config 64 | base: 65 | apiVersion: helm.crossplane.io/v1beta1 66 | kind: ProviderConfig 67 | spec: 68 | identity: 69 | type: GoogleApplicationCredentials 70 | source: Secret 71 | secretRef: 72 | name: gcp-account 73 | namespace: crossplane-system 74 | key: service-account 75 | credentials: 76 | source: Secret 77 | secretRef: 78 | key: kubeconfig 79 | patches: 80 | - fromFieldPath: spec.claimRef.namespace 81 | toFieldPath: spec.credentials.secretRef.namespace 82 | - fromFieldPath: spec.claimRef.name 83 | toFieldPath: spec.credentials.secretRef.name 84 | transforms: 85 | - type: string 86 | string: 87 | fmt: "%s-secret" 88 | - fromFieldPath: spec.claimRef.name 89 | toFieldPath: metadata.name 90 | transforms: 91 | - type: string 92 | string: 93 | fmt: "%s-helm-provider-config" 94 | readinessChecks: 95 | - type: None 96 | - name: gke-dev-cluster-k8s-provider-config 97 | base: 98 | apiVersion: kubernetes.crossplane.io/v1alpha1 99 | kind: ProviderConfig 100 | spec: 101 | identity: 102 | type: GoogleApplicationCredentials 103 | source: Secret 104 | secretRef: 105 | name: gcp-account 106 | namespace: crossplane-system 107 | key: service-account 108 | credentials: 109 | source: Secret 110 | secretRef: 111 | key: kubeconfig 112 | patches: 113 | - fromFieldPath: spec.claimRef.namespace 114 | toFieldPath: spec.credentials.secretRef.namespace 115 | - fromFieldPath: spec.claimRef.name 116 | toFieldPath: spec.credentials.secretRef.name 117 | transforms: 118 | - type: string 119 | string: 120 | fmt: "%s-secret" 121 | - fromFieldPath: spec.claimRef.name 122 | toFieldPath: metadata.name 123 | transforms: 124 | - type: string 125 | string: 126 | fmt: "%s-k8s-provider-config" 127 | readinessChecks: 128 | - type: None 129 | - name: gke-dev-cluster-argocd-setup 130 | base: 131 | apiVersion: helm.crossplane.io/v1beta1 132 | kind: Release 133 | spec: 134 | forProvider: 135 | chart: 136 | name: argo-cd 137 | repository: https://argoproj.github.io/argo-helm 138 | version: 2.3.3 139 | namespace: argocd 140 | set: 141 | - name: server.service.type 142 | value: LoadBalancer 143 | patches: 144 | - fromFieldPath: spec.claimRef.name 145 | toFieldPath: metadata.name 146 | transforms: 147 | - type: string 148 | string: 149 | fmt: "%s-helm-argocd" 150 | - fromFieldPath: spec.claimRef.name 151 | toFieldPath: spec.providerConfigRef.name 152 | transforms: 153 | - type: string 154 | string: 155 | fmt: "%s-helm-provider-config" -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-2-CreateProductTeamsKubernetesCluster/Platform-OPS/cluster-xrd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xgcpclusters.learn.unified.devops 5 | spec: 6 | group: learn.unified.devops 7 | names: 8 | kind: XGCPCluster 9 | plural: xgcpclusters 10 | claimNames: 11 | kind: GCPCluster 12 | plural: gcpclusters 13 | versions: 14 | - name: v1alpha1 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | nodeCount: 28 | description: number of nodes in the cluster 29 | type: integer 30 | size: 31 | description: type of the machine type 32 | type: string 33 | enum: 34 | - BIG 35 | - SMALL 36 | required: 37 | - nodeCount 38 | - size 39 | required: 40 | - parameters -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-3-GitProjectOnboarding/Additional-Steps.md: -------------------------------------------------------------------------------- 1 | # Create a new gitlab repo group for the product that will hold all repos. In our case we created a group called project-x 2 | 3 | # Add your registry credentials as CI/CD variables for the full group. We have created REG_PASSWORD and REG_USER which is used in the gitlab pipeline to login to Docker Hub to push and pull the images -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-3-GitProjectOnboarding/Application-OPS/gitproject-claim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: learn.unified.devops/v1alpha1 2 | kind: GitProject 3 | metadata: 4 | name: micro-frontend-one 5 | namespace: product-a 6 | spec: 7 | compositionRef: 8 | name: gitprojects-composition 9 | parameters: 10 | template: react-web 11 | gitlabGroupID: 52372004 -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-3-GitProjectOnboarding/Platform-OPS/gitproject-xrd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xgitprojects.learn.unified.devops 5 | spec: 6 | group: learn.unified.devops 7 | names: 8 | kind: XGitProject 9 | plural: xgitprojects 10 | claimNames: 11 | kind: GitProject 12 | plural: gitprojects 13 | connectionSecretKeys: 14 | - gitlabToken 15 | - gitlabProjectURL 16 | versions: 17 | - name: v1alpha1 18 | served: true 19 | referenceable: true 20 | schema: 21 | openAPIV3Schema: 22 | type: object 23 | properties: 24 | spec: 25 | type: object 26 | properties: 27 | parameters: 28 | type: object 29 | properties: 30 | template: 31 | description: Name of the product to pick correct template repo 32 | type: string 33 | enum: 34 | - react-web 35 | - node-backend 36 | - spring-boot-web 37 | - spring-boot-api 38 | gitlabGroupID: 39 | description: the gitlab group under which new project repo should be created 40 | type: integer 41 | required: 42 | - template 43 | - gitlabGroupID 44 | required: 45 | - parameters 46 | status: 47 | type: object 48 | properties: 49 | projectRepo: 50 | description: Address of the newly created react GitLab project. 51 | type: string 52 | -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-3-GitProjectOnboarding/Platform-OPS/gitprojects-composition.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: gitprojects-composition 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: learn.unified.devops/v1alpha1 8 | kind: XGitProject 9 | resources: 10 | - name: gitlab-project 11 | base: 12 | apiVersion: projects.gitlab.crossplane.io/v1alpha1 13 | kind: Project 14 | spec: 15 | providerConfigRef: 16 | name: # Patch 17 | forProvider: 18 | visibility: public 19 | publicBuilds: true 20 | patches: 21 | - fromFieldPath: spec.claimRef.name 22 | toFieldPath: metadata.name 23 | - fromFieldPath: spec.claimRef.namespace 24 | toFieldPath: spec.providerConfigRef.name 25 | - fromFieldPath: spec.claimRef.namespace 26 | toFieldPath: spec.writeConnectionSecretToRef.namespace 27 | - fromFieldPath: spec.claimRef.name 28 | toFieldPath: spec.writeConnectionSecretToRef.name 29 | transforms: 30 | - type: string 31 | string: 32 | fmt: "%s-repo-key" 33 | - fromFieldPath: spec.parameters.gitlabGroupID 34 | toFieldPath: spec.forProvider.namespaceId 35 | - fromFieldPath: spec.claimRef.name 36 | toFieldPath: spec.forProvider.description 37 | transforms: 38 | - type: string 39 | string: 40 | fmt: "The %s react project" 41 | - type: FromCompositeFieldPath 42 | fromFieldPath: spec.parameters.template 43 | toFieldPath: spec.forProvider.importUrl 44 | transforms: 45 | - type: map 46 | map: 47 | react-web: https://gitlab.com/unified.devops/react-template.git 48 | node-backend: https://gitlab.com/unified.devops/react-template.git 49 | spring-boot-web: https://gitlab.com/unified.devops/react-template.git 50 | spring-boot-api: https://gitlab.com/unified.devops/react-template.git 51 | - type: ToCompositeFieldPath 52 | fromFieldPath: status.atProvider.httpUrlToRepo 53 | toFieldPath: status.projectRepo 54 | connectionDetails: 55 | - name: gitlabToken 56 | fromConnectionSecretKey: runnersToken 57 | - name: gitlabProjectURL 58 | fromFieldPath: status.atProvider.httpUrlToRepo -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-4-WebApplication/Application-OPS/Claim-Application.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: learn.unified.devops/v1alpha1 2 | kind: WebApplication 3 | metadata: 4 | name: micro-frontend-one 5 | namespace: product-a 6 | spec: 7 | compositionRef: 8 | name: web-application-dev 9 | parameters: 10 | productGitGroup: unified-devops-project-x 11 | databaseSize: SMALL -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-4-WebApplication/Platform-OPS/Application/web-application-composition-dev.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: web-application-dev 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: learn.unified.devops/v1alpha1 8 | kind: XWebApplication 9 | resources: 10 | - name: application-namespace 11 | base: 12 | apiVersion: kubernetes.crossplane.io/v1alpha1 13 | kind: Object 14 | spec: 15 | forProvider: 16 | manifest: 17 | apiVersion: v1 18 | kind: Namespace 19 | metadata: 20 | name: # to be patched 21 | patches: 22 | - fromFieldPath: spec.claimRef.namespace 23 | toFieldPath: spec.providerConfigRef.name 24 | transforms: 25 | - type: string 26 | string: 27 | fmt: "%s-cluster-k8s-provider-config" 28 | - fromFieldPath: spec.claimRef.namespace 29 | toFieldPath: spec.forProvider.manifest.metadata.name 30 | - name: argocd-application-gitops 31 | base: 32 | apiVersion: kubernetes.crossplane.io/v1alpha1 33 | kind: Object 34 | spec: 35 | forProvider: 36 | manifest: 37 | apiVersion: argoproj.io/v1alpha1 38 | kind: Application 39 | metadata: 40 | name: # to be patched 41 | namespace: argocd 42 | spec: 43 | project: default 44 | source: 45 | repoURL: # to be patched 46 | targetRevision: HEAD 47 | path: template-helm 48 | helm: 49 | releaseName: # To be patched 50 | parameters: 51 | - name: "image.repository" 52 | value: # To be patched 53 | - name: "image.tag" 54 | value: latest 55 | - name: "service.port" 56 | value: "3000" 57 | destination: 58 | server: https://kubernetes.default.svc 59 | namespace: # to be patched 60 | syncPolicy: 61 | automated: 62 | prune: true 63 | selfHeal: true 64 | syncOptions: 65 | - CreateNamespace=true 66 | patches: 67 | - fromFieldPath: spec.claimRef.namespace 68 | toFieldPath: spec.providerConfigRef.name 69 | transforms: 70 | - type: string 71 | string: 72 | fmt: "%s-cluster-k8s-provider-config" 73 | - fromFieldPath: spec.claimRef.name 74 | toFieldPath: spec.forProvider.manifest.metadata.name 75 | transforms: 76 | - type: string 77 | string: 78 | fmt: "%s-argo" 79 | - type: CombineFromComposite 80 | toFieldPath: spec.forProvider.manifest.spec.source.repoURL 81 | combine: 82 | variables: 83 | - fromFieldPath: spec.parameters.productGitGroup 84 | - fromFieldPath: spec.claimRef.name 85 | strategy: string 86 | string: 87 | fmt: "https://gitlab.com/%s/%s.git" 88 | - fromFieldPath: spec.claimRef.namespace 89 | toFieldPath: spec.forProvider.manifest.spec.destination.namespace 90 | - fromFieldPath: spec.claimRef.name 91 | toFieldPath: spec.forProvider.manifest.spec.source.helm.releaseName 92 | - fromFieldPath: spec.claimRef.name 93 | toFieldPath: spec.forProvider.manifest.spec.source.helm.parameters[0].value 94 | transforms: 95 | - type: string 96 | string: 97 | fmt: "arunramakani/%s" 98 | - name: db 99 | base: 100 | apiVersion: learn.unified.devops/v1alpha1 101 | kind: XGCPdb 102 | spec: 103 | parameters: 104 | size: BIG 105 | product: default 106 | application: default 107 | patches: 108 | - fromFieldPath: spec.claimRef.namespace 109 | toFieldPath: spec.parameters.product 110 | - fromFieldPath: spec.parameters.size 111 | toFieldPath: spec.parameters.size 112 | - fromFieldPath: spec.claimRef.name 113 | toFieldPath: spec.parameters.application -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-4-WebApplication/Platform-OPS/Application/web-application-xrd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xwebapplications.learn.unified.devops 5 | spec: 6 | group: learn.unified.devops 7 | names: 8 | kind: XWebApplication 9 | plural: xwebapplications 10 | claimNames: 11 | kind: WebApplication 12 | plural: webapplications 13 | versions: 14 | - name: v1alpha1 15 | served: true 16 | referenceable: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | parameters: 25 | type: object 26 | properties: 27 | productGitGroup: 28 | type: string 29 | databaseSize: 30 | type: string 31 | required: 32 | - productGitGroup 33 | - databaseSize 34 | required: 35 | - parameters -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-4-WebApplication/Platform-OPS/DB/db-composition-MySQL.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: mysql 5 | spec: 6 | compositeTypeRef: 7 | apiVersion: learn.unified.devops/v1alpha1 8 | kind: XGCPdb 9 | resources: 10 | - name: cloudsqlinstance 11 | base: 12 | apiVersion: database.gcp.crossplane.io/v1beta1 13 | kind: CloudSQLInstance 14 | spec: 15 | forProvider: 16 | databaseVersion: MYSQL_5_7 17 | region: us-central1 18 | settings: 19 | tier: db-g1-small 20 | dataDiskSizeGb: 20 21 | patches: 22 | - fromFieldPath: spec.parameters.application 23 | toFieldPath: metadata.name 24 | - fromFieldPath: spec.parameters.product 25 | toFieldPath: spec.providerConfigRef.name 26 | - fromFieldPath: spec.parameters.product 27 | toFieldPath: spec.writeConnectionSecretToRef.namespace 28 | - fromFieldPath: spec.parameters.application 29 | toFieldPath: spec.writeConnectionSecretToRef.name 30 | transforms: 31 | - type: string 32 | string: 33 | fmt: "%s-db-secret" 34 | - type: FromCompositeFieldPath 35 | fromFieldPath: spec.parameters.size 36 | toFieldPath: spec.forProvider.settings.tier 37 | transforms: 38 | - type: map 39 | map: 40 | BIG: db-n1-standard-1 41 | SMALL: db-g1-small 42 | - type: FromCompositeFieldPath 43 | fromFieldPath: spec.parameters.size 44 | toFieldPath: spec.forProvider.settings.dataDiskSizeGb 45 | transforms: 46 | - type: map 47 | map: 48 | BIG: "40" 49 | SMALL: "20" 50 | - type: convert 51 | convert: 52 | toType: int 53 | connectionDetails: 54 | - name: hostname 55 | fromConnectionSecretKey: hostname -------------------------------------------------------------------------------- /Chapter10/Hands-on-example/Step-4-WebApplication/Platform-OPS/DB/db-xrd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: xgcpdbs.learn.unified.devops 5 | spec: 6 | group: learn.unified.devops 7 | names: 8 | kind: XGCPdb 9 | plural: xgcpdbs 10 | versions: 11 | - name: v1alpha1 12 | served: true 13 | referenceable: true 14 | schema: 15 | openAPIV3Schema: 16 | type: object 17 | properties: 18 | spec: 19 | type: object 20 | properties: 21 | parameters: 22 | type: object 23 | properties: 24 | size: 25 | type: string 26 | product: 27 | type: string 28 | application: 29 | type: string 30 | required: 31 | - size 32 | - product 33 | - application 34 | required: 35 | - parameters -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # End to End Automation with Kubernetes and Crossplane 5 | Early Access 6 | 7 | This is the code repository for [End to End Automation with Kubernetes and Crossplane](https://www.packtpub.com/cloud-networking/end-to-end-automation-with-kubernetes-and-crossplane?utm_source=github&utm_medium=repository&utm_campaign=9781801811545), published by Packt. 8 | 9 | **Develop a control plane-based platform for unified infrastructure, services, and application automation** 10 | 11 | ## What is this book about? 12 | In the last few years, countless organizations have taken advantage of the disruptive app deployment operating model provided by Kubernetes. With the launch of Crossplane, the same benefits are coming to the world of infrastructure provisioning and management. The limitations of Infrastructure as Code with respect to drift management, role-based access control, team collaboration, and weak contract are making people move toward control-plane-based infrastructure automation, but setting it up requires a lot of know-how and effort. 13 | 14 | This book covers the following exciting features: 15 | * Understand the context of Kubernetes-based infrastructure automation 16 | * Get to grips with Crossplane concepts with the help of practical examples 17 | * Extend Crossplane to build a modern infrastructure automation platform 18 | * Use the right configuration management tools in the Kubernetes environment 19 | * Explore patterns to unify application and infrastructure automation 20 | * Discover top engineering practices for infrastructure platform as a product 21 | 22 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1801811547) today! 23 | 24 | https://www.packtpub.com/ 26 | 27 | ## Instructions and Navigations 28 | All of the code is organized into folders. For example, Chapter03. 29 | 30 | A block of code is set as follows: 31 | ``` 32 | # List all resources 33 | kubectl api-resources 34 | 35 | # List resources in the "apps" API group 36 | kubectl api-resources --api-group=apps 37 | 38 | # List resources in the "networking.k8s.io" API group 39 | kubectl api-resources --api-group=networking.k8s.io 40 | ``` 41 | Any command-line input or output is written as follows: 42 | ``` 43 | % kubectl get all -n crossplane-system 44 | helm delete crossplane --namespace crossplane-system 45 | ``` 46 | 47 | **Following is what you need for this book:** 48 | This book is for cloud architects, platform engineers, infrastructure or application operators, and Kubernetes enthusiasts who want to simplify infrastructure and application automation. A basic understanding of Kubernetes and its building blocks like Pod, Deployment, Service, and Namespace is needed before you can get started with this book. 49 | 50 | With the following software and hardware list you can run all code files present in the book (Chapter 1-11). 51 | ### Software and Hardware List 52 | | Software required | OS required | 53 | | ------------------------------------ | ----------------------------------- | 54 | | Kind Kubernetes cluster - v1.21.1 | Windows, Mac OS X, and Linux (Any) | 55 | | Crossplane -v.15.0 (minimum Kubernetes v1.16.0) | | 56 | | Helm v3.8.0 (minimum Kubernetes v3.0.0) | | 57 | | GCP Crossplane provider - v0.18.0 | | 58 | | AWS Crossplane provider - v0.23.0 | | 59 | 60 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it](https://packt.link/1j9JK). 61 | 62 | 65 | ## Errata 66 | 67 | * Page 184,185: Command examples should be **"vela addon"** instead of "vela add-on" 68 | 69 | 72 | 73 | ### Related products 74 | * The Kubernetes Bible [[Packt]](https://www.packtpub.com/product/the-kubernetes-bible/9781838827694?utm_source=github&utm_medium=repository&utm_campaign=9781838827694) [[Amazon]](https://www.amazon.com/dp/1838827692) 75 | 76 | * Continuous Delivery with Docker and Jenkins - Third Edition [[Packt]](https://www.packtpub.com/product/continuous-delivery-with-docker-and-jenkins/9781803237480?utm_source=github&utm_medium=repository&utm_campaign=9781803237480) [[Amazon]](https://www.amazon.com/dp/1803237481) 77 | 78 | ## Get to Know the Author 79 | **Arun Ramakani** 80 | is a passionate distributed platform development and a technology blogging expert living in Dubai, a dynamic city where many cultures meet. He is currently working as a Technology Architect at PwC, specializing in Evolutionary Architecture Practices, Kubernetes DevOps, Cloud-Native Apps, and Microservices. He has over a decade of experience working in a variety of different technology, domain, and teams. He has been part of many digital transformation journeys in the last few years. This book is an inspiration from one of his recent works. He is enthusiastic about learning in public and committed to helping individuals in their cloud-native learning journey. 81 | 82 | 83 | ### Download a free PDF 84 | 85 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
86 |

https://packt.link/free-ebook/9781801811545

--------------------------------------------------------------------------------