diff --git a/.gitignore b/.gitignore index e0e0cec..b7bcfcb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,11 @@ __pycache__ # OpenTofu state .terraform* -terraform.tfstate* \ No newline at end of file +terraform.tfstate* + +# CDKTF +dist/ +imports/* +!imports/__init__.py +cdktf.out +cdktf.log \ No newline at end of file diff --git a/pilot/provision/cdktf-demo/Pipfile b/pilot/provision/cdktf-demo/Pipfile new file mode 100644 index 0000000..894400c --- /dev/null +++ b/pilot/provision/cdktf-demo/Pipfile @@ -0,0 +1,12 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[requires] +python_version = "3" + +[packages] +cdktf = "~=0.20.8" +pytest = "*" +cdktf-cdktf-provider-digitalocean = "~=11.5.2" diff --git a/pilot/provision/cdktf-demo/Pipfile.lock b/pilot/provision/cdktf-demo/Pipfile.lock new file mode 100644 index 0000000..aad8948 --- /dev/null +++ b/pilot/provision/cdktf-demo/Pipfile.lock @@ -0,0 +1,151 @@ +{ + "_meta": { + "hash": { + "sha256": "034b60286cee8ece9a70b1f6be878fce1d98fd02f968070932a3a72f8810ade4" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "attrs": { + "hashes": [ + "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", + "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2.0" + }, + "cattrs": { + "hashes": [ + "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108", + "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f" + ], + "markers": "python_version >= '3.8'", + "version": "==23.2.3" + }, + "cdktf": { + "hashes": [ + "sha256:a16ff42ee678e50433ad3d548b86aad3f21c041990e21781860db6e0ae4a97db", + "sha256:d78879a03bf6523102672a47e7f8b5b1dfedce77ca185269ceb6590c11217968" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==0.20.8" + }, + "cdktf-cdktf-provider-digitalocean": { + "hashes": [ + "sha256:1ec5e335767ec1e14768ccb066742a40d262567a054a4884b3dc351ad900acad", + "sha256:d9ad6f253ac8cf1b9bf39aa1bdc5e6202ad361d0f25b50e9819b21f47ea6c7a3" + ], + "index": "pypi", + "markers": "python_version ~= '3.8'", + "version": "==11.5.2" + }, + "constructs": { + "hashes": [ + "sha256:2972f514837565ff5b09171cfba50c0159dfa75ee86a42921ea8c86f2941b3d2", + "sha256:518551135ec236f9cc6b86500f4fbbe83b803ccdc6c2cb7684e0b7c4d234e7b1" + ], + "markers": "python_version ~= '3.7'", + "version": "==10.3.0" + }, + "importlib-resources": { + "hashes": [ + "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c", + "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145" + ], + "markers": "python_version >= '3.8'", + "version": "==6.4.0" + }, + "iniconfig": { + "hashes": [ + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, + "jsii": { + "hashes": [ + "sha256:043c4d3d0d09af3c7265747f4da9c95770232477f75c846640df4c63d01b19cb", + "sha256:b78b87f8316560040ad0b9dca1682d73b6532a33acf4ecf56185d1ae5edb54fa" + ], + "markers": "python_version ~= '3.8'", + "version": "==1.101.0" + }, + "packaging": { + "hashes": [ + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + ], + "markers": "python_version >= '3.8'", + "version": "==24.1" + }, + "pluggy": { + "hashes": [ + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "publication": { + "hashes": [ + "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6", + "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4" + ], + "version": "==0.0.3" + }, + "pytest": { + "hashes": [ + "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", + "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==8.2.2" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.0.post0" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, + "typeguard": { + "hashes": [ + "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4", + "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1" + ], + "markers": "python_full_version >= '3.5.3'", + "version": "==2.13.3" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + } + }, + "develop": {} +} diff --git a/pilot/provision/cdktf-demo/README.md b/pilot/provision/cdktf-demo/README.md new file mode 100644 index 0000000..85132d2 --- /dev/null +++ b/pilot/provision/cdktf-demo/README.md @@ -0,0 +1,621 @@ +# Beginning with CDKTF +Cloud Development Kit with Terraform + +## Install +Install CDKTF with NPM + +```sh +$ npm install --global cdktf-cli@latest +``` + +Also needs `pipenv` + +```sh +pip install pipenv +``` + +Reference: https://developer.hashicorp.com/terraform/tutorials/cdktf/cdktf-install?variants=cdk-language%3Apython + +## Initialize + +Initialize project directory +```sh +$ mkdir cdktf-demo +$ cd cdktf-demo +$ cdktf init --template=python --local --providers=digitalocean/digitalocean +``` + +``` +[2024-07-15T17:18:33.723] [INFO] default - Unable to determine Terraform version: Error: Terraform CLI not present - Please install a current version https://learn.hashicorp.com/terraform/getting-started/install.html +Note: By supplying '--local' option you have chosen local storage mode for storing the state of your stack. +This means that your Terraform state file will be stored locally on disk in a file 'terraform..tfstate' in the root of your project. +[2024-07-15T17:18:33.782] [INFO] default - Unable to determine Terraform version: Error: Terraform CLI not present - Please install a current version https://learn.hashicorp.com/terraform/getting-started/install.html +? Project Name cdktf-demo +? Project Description A simple getting started project for cdktf. +? Do you want to send crash reports to the CDKTF team? Refer to https://developer.hashicorp.com/terraform/cdktf/create-and-deploy/configuration-file#enable-crash-reporting-for-the-cli for more information no +Courtesy Notice: Pipenv found itself running within a virtual environment, so it will automatically use that environment, instead of creating its own for any project. You can set PIPENV_IGNORE_VIRTUALENVS=1 to force pipenv to ignore that environment and create its own instead. You can set PIPENV_VERBOSITY=-1 to suppress this warning. +Pipfile.lock not found, creating... +Locking [packages] dependencies... +Locking [dev-packages] dependencies... +Updated Pipfile.lock (4e61a4ba9e6f02f50f68627253af5ababd9b1b4c1e10294e48158e1f42c0c5a6)! +To activate this project's virtualenv, run pipenv shell. +Alternatively, run a command inside the virtualenv with pipenv run. +To activate this project's virtualenv, run pipenv shell. +Alternatively, run a command inside the virtualenv with pipenv run. +Installing dependencies from Pipfile.lock (c0c5a6)... +Courtesy Notice: Pipenv found itself running within a virtual environment, so it will automatically use that environment, instead of creating its own for any project. You can set PIPENV_IGNORE_VIRTUALENVS=1 to force pipenv to ignore that environment and create its own instead. You can set PIPENV_VERBOSITY=-1 to suppress this warning. +Installing cdktf~=0.20.8... +Resolving cdktf~=0.20.8... +Added cdktf to Pipfile's [packages] ... +✔ Installation Succeeded +Pipfile.lock (c0c5a6) out of date: run `pipfile lock` to update to (813b71)... +Running $ pipenv lock then $ pipenv sync. +Locking [packages] dependencies... +Building requirements... +Resolving dependencies... +✔ Success! +Locking [dev-packages] dependencies... +Updated Pipfile.lock (7f87fbbb4630d4c1d03d4ec00579a88eb8c446f6f67d713759079ac767813b71)! +To activate this project's virtualenv, run pipenv shell. +Alternatively, run a command inside the virtualenv with pipenv run. +Installing dependencies from Pipfile.lock (813b71)... +All dependencies are now up-to-date! +To activate this project's virtualenv, run pipenv shell. +Alternatively, run a command inside the virtualenv with pipenv run. +Installing dependencies from Pipfile.lock (813b71)... +Courtesy Notice: Pipenv found itself running within a virtual environment, so it will automatically use that environment, instead of creating its own for any project. You can set PIPENV_IGNORE_VIRTUALENVS=1 to force pipenv to ignore that environment and create its own instead. You can set PIPENV_VERBOSITY=-1 to suppress this warning. +Installing pytest... +Resolving pytest... +Added pytest to Pipfile's [packages] ... +✔ Installation Succeeded +Pipfile.lock (813b71) out of date: run `pipfile lock` to update to (4b37ac)... +Running $ pipenv lock then $ pipenv sync. +Locking [packages] dependencies... +Building requirements... +Resolving dependencies... +✔ Success! +Locking [dev-packages] dependencies... +Updated Pipfile.lock (bcd1e1ca83ad80fd3a755c93c9b682c802732ef5d3bcf812b41a76b3944b37ac)! +To activate this project's virtualenv, run pipenv shell. +Alternatively, run a command inside the virtualenv with pipenv run. +Installing dependencies from Pipfile.lock (4b37ac)... +All dependencies are now up-to-date! +To activate this project's virtualenv, run pipenv shell. +Alternatively, run a command inside the virtualenv with pipenv run. +Installing dependencies from Pipfile.lock (4b37ac)... +======================================================================================================== + + Your cdktf Python project is ready! + + cat help Prints this message + + Compile: + pipenv run ./main.py Compile and run the python code. + + Synthesize: + cdktf synth [stack] Synthesize Terraform resources to cdktf.out/ + + Diff: + cdktf diff [stack] Perform a diff (terraform plan) for the given stack + + Deploy: + cdktf deploy [stack] Deploy the given stack + + Destroy: + cdktf destroy [stack] Destroy the given stack + + Learn more about using modules and providers https://cdk.tf/modules-and-providers + +Use Providers: + + You can add prebuilt providers (if available) or locally generated ones using the add command: + + cdktf provider add "aws@~>3.0" null kreuzwerker/docker + + You can find all prebuilt providers on PyPI: https://pypi.org/user/cdktf-team/ + You can also install these providers directly through pipenv: + + pipenv install cdktf-cdktf-provider-aws + pipenv install cdktf-cdktf-provider-google + pipenv install cdktf-cdktf-provider-azurerm + pipenv install cdktf-cdktf-provider-docker + pipenv install cdktf-cdktf-provider-github + pipenv install cdktf-cdktf-provider-null + + You can also build any module or provider locally. Learn more: https://cdk.tf/modules-and-providers + +======================================================================================================== +[2024-07-15T17:18:57.287] [INFO] default - Checking whether pre-built provider exists for the following constraints: + provider: digitalocean/digitalocean + version : latest + language: python + cdktf : 0.20.8 + +[2024-07-15T17:19:05.780] [INFO] default - Found pre-built provider. +Installing package cdktf-cdktf-provider-digitalocean @ 11.5.2 using pipenv. +Installing cdktf-cdktf-provider-digitalocean~=11.5.2... +Resolving cdktf-cdktf-provider-digitalocean~=11.5.2... +Added cdktf-cdktf-provider-digitalocean to Pipfile's [packages] ... +✔ Installation Succeeded +Pipfile.lock (4b37ac) out of date: run `pipfile lock` to update to (10ade4)... +Running $ pipenv lock then $ pipenv sync. +Locking [packages] dependencies... +Building requirements... +Resolving dependencies... +✔ Success! +Locking [dev-packages] dependencies... +Updated Pipfile.lock (034b60286cee8ece9a70b1f6be878fce1d98fd02f968070932a3a72f8810ade4)! +To activate this project's virtualenv, run pipenv shell. +Alternatively, run a command inside the virtualenv with pipenv run. +Installing dependencies from Pipfile.lock (10ade4)... +All dependencies are now up-to-date! +To activate this project's virtualenv, run pipenv shell. +Alternatively, run a command inside the virtualenv with pipenv run. +Installing dependencies from Pipfile.lock (10ade4)... +Package installed. +``` + + +## Write + +Refer to `main.py` + +This is equivalent of writing a HCL file + +Few quirks +- Typecasts + - `Droplet.ssh_keys` expects `Sequence[str]`. HCL file implies `int` + - `Fn.tonumber` + - `Droplet.id` is a `str`, `VolumeAttachment.droplet_id` exepect an `int` +- Variables + - `variable.string_value` to actually access the value +## Debug +```sh +$ cdktf debug +``` +``` +cdktf debug +language: python +cdktf-cli: 0.20.8 +node: v18.12.1 +cdktf: 0.20.8 +constructs: 10.3.0 +jsii: 1.101.0 +terraform: Error: Usage Error: Unknown: Error loading terraform version Error: spawn terraform ENOENT +arch: x64 +os: linux 6.9.9-060909-generic +python: Python 3.12.4 +pip: pip 24.1.2 from /home/aditya/Frappe/benches/pilot/env/lib/python3.12/site-packages/pip (python 3.12) +pipenv: pipenv, version 2024.0.1 +providers +cdktf-cdktf-provider-digitalocean (PREBUILT) + terraform provider version: 2.39.2 + prebuilt provider version: 11.5.2 + cdktf version: ^0.20.0 +``` + +We haven't install terraform. Need to tell cdktf to use tofu binary with + +```sh +export TERRAFORM_BINARY_NAME=tofu +``` +Now CDKTF should work fine +``` +... +terraform: 1.7.3 +... +``` + +Without this `plan` will fail with `execvp(3) failed.: No such file or directory` + +## Plan +This is more or less like `tofu plan` + +**Note**: Need to pass `do_token` with `--var "do_token="` +```sh +$ cdktf plan +``` +``` +⠇ Synthesizing +cdktf-demo Initializing the backend... +cdktf-demo Initializing provider plugins... + - Reusing previous version of digitalocean/digitalocean from the dependency lock file +cdktf-demo - Using previously-installed digitalocean/digitalocean v2.39.2 + + OpenTofu has been successfully initialized! + + You may now begin working with OpenTofu. Try running "tofu plan" to see + any changes that are required for your infrastructure. All OpenTofu commands + should now work. + + If you ever set or change modules or backend configuration for OpenTofu, + rerun this command to reinitialize your working directory. If you forget, other + commands will detect it and remind you to do so if necessary. +cdktf-demo - Fetching digitalocean/digitalocean 2.39.2 for linux_amd64... +cdktf-demo - Retrieved digitalocean/digitalocean 2.39.2 for linux_amd64 (signed, key ID F82037E524B9C0E8) + - Obtained digitalocean/digitalocean checksums for linux_amd64; All checksums for this platform were already tracked in the lock file +cdktf-demo Success! OpenTofu has validated the lock file and found no need for changes. +cdktf-demo OpenTofu used the selected providers to generate the following execution + plan. Resource actions are indicated with the following symbols: + + create + + OpenTofu will perform the following actions: +cdktf-demo # digitalocean_droplet.example_droplet (example_droplet) will be created + + resource "digitalocean_droplet" "example_droplet" { + + backups = false + + created_at = (known after apply) + + disk = (known after apply) + + graceful_shutdown = false + + id = (known after apply) + + image = "ubuntu-24-04-x64" + + ipv4_address = (known after apply) + + ipv4_address_private = (known after apply) + + ipv6 = false + + ipv6_address = (known after apply) + + locked = (known after apply) + + memory = (known after apply) + + monitoring = false + + name = "pilot-test-tofu-droplet-1" + + price_hourly = (known after apply) + + price_monthly = (known after apply) + + private_networking = (known after apply) + + region = "blr1" + + resize_disk = true + + size = "s-1vcpu-1gb" + + ssh_keys = [ + + "39020628", + ] + + status = (known after apply) + + urn = (known after apply) + + vcpus = (known after apply) + + volume_ids = (known after apply) + + vpc_uuid = (known after apply) + } + + # digitalocean_project.example_project (example_project) will be created + + resource "digitalocean_project" "example_project" { + + created_at = (known after apply) + + description = "Project for playing around with Tofu" + + environment = "Development" + + id = (known after apply) + + is_default = false + + name = "Pilot Tofu Playground" + + owner_id = (known after apply) + + owner_uuid = (known after apply) + + purpose = "Web Application" + + resources = (known after apply) + + updated_at = (known after apply) + } + + # digitalocean_volume.example_volume (example_volume) will be created + + resource "digitalocean_volume" "example_volume" { + + description = "an example volume" + + droplet_ids = (known after apply) + + filesystem_label = (known after apply) + + filesystem_type = (known after apply) + + id = (known after apply) + + initial_filesystem_type = "ext4" + + name = "pilot-test-tofu-volume-1" + + region = "blr1" + + size = 10 + + urn = (known after apply) + } + + # digitalocean_volume_attachment.example_volume_attachment (example_volume_attachment) will be created + + resource "digitalocean_volume_attachment" "example_volume_attachment" { + + droplet_id = (known after apply) + + id = (known after apply) + + volume_id = (known after apply) + } + + # digitalocean_vpc.example_vpc (example_vpc) will be created + + resource "digitalocean_vpc" "example_vpc" { + + created_at = (known after apply) + + default = (known after apply) + + id = (known after apply) + + ip_range = "10.10.10.0/24" + + name = "pilot-test-tofu-vpc-1" + + region = "blr1" + + urn = (known after apply) + } + + Plan: 5 to add, 0 to change, 0 to destroy. + + ───────────────────────────────────────────────────────────────────────────── + + Saved the plan to: plan + + To perform exactly these actions, run the following command to apply: + tofu apply "plan" +``` + + +## Deploy +Same as `tofu apply`. This handles dependencies across multiple stacks, whatever that means. +```sh +$ cdktf deploy +``` +``` +⠦ Synthesizing +cdktf-demo Initializing the backend... +cdktf-demo Initializing provider plugins... + - Reusing previous version of digitalocean/digitalocean from the dependency lock file +cdktf-demo - Using previously-installed digitalocean/digitalocean v2.39.2 + + OpenTofu has been successfully initialized! + + You may now begin working with OpenTofu. Try running "tofu plan" to see + any changes that are required for your infrastructure. All OpenTofu commands + should now work. + + If you ever set or change modules or backend configuration for OpenTofu, + rerun this command to reinitialize your working directory. If you forget, other + commands will detect it and remind you to do so if necessary. +cdktf-demo - Fetching digitalocean/digitalocean 2.39.2 for linux_amd64... +cdktf-demo - Retrieved digitalocean/digitalocean 2.39.2 for linux_amd64 (signed, key ID F82037E524B9C0E8) + - Obtained digitalocean/digitalocean checksums for linux_amd64; All checksums for this platform were already tracked in the lock file +cdktf-demo Success! OpenTofu has validated the lock file and found no need for changes. +cdktf-demo OpenTofu used the selected providers to generate the following execution plan. + Resource actions are indicated with the following symbols: + + create + + OpenTofu will perform the following actions: +cdktf-demo # digitalocean_droplet.example_droplet (example_droplet) will be created + + resource "digitalocean_droplet" "example_droplet" { + + backups = false + + created_at = (known after apply) + + disk = (known after apply) + + graceful_shutdown = false + + id = (known after apply) + + image = "ubuntu-24-04-x64" + + ipv4_address = (known after apply) + + ipv4_address_private = (known after apply) + + ipv6 = false + + ipv6_address = (known after apply) + + locked = (known after apply) + + memory = (known after apply) + + monitoring = false + + name = "pilot-test-tofu-droplet-1" + + price_hourly = (known after apply) + + price_monthly = (known after apply) + + private_networking = (known after apply) + + region = "blr1" + + resize_disk = true + + size = "s-1vcpu-1gb" + + ssh_keys = [ + + "39020628", + ] + + status = (known after apply) + + urn = (known after apply) + + vcpus = (known after apply) + + volume_ids = (known after apply) + + vpc_uuid = (known after apply) + } + + # digitalocean_project.example_project (example_project) will be created + + resource "digitalocean_project" "example_project" { + + created_at = (known after apply) + + description = "Project for playing around with Tofu" + + environment = "Development" + + id = (known after apply) + + is_default = false + + name = "Pilot Tofu Playground" + + owner_id = (known after apply) + + owner_uuid = (known after apply) + + purpose = "Web Application" + + resources = (known after apply) + + updated_at = (known after apply) + } + + # digitalocean_volume.example_volume (example_volume) will be created + + resource "digitalocean_volume" "example_volume" { + + description = "an example volume" + + droplet_ids = (known after apply) + + filesystem_label = (known after apply) + + filesystem_type = (known after apply) + + id = (known after apply) + + initial_filesystem_type = "ext4" + + name = "pilot-test-tofu-volume-1" + + region = "blr1" + + size = 10 + + urn = (known after apply) + } + + # digitalocean_volume_attachment.example_volume_attachment (example_volume_attachment) will be created + + resource "digitalocean_volume_attachment" "example_volume_attachment" { + + droplet_id = (known after apply) + + id = (known after apply) + + volume_id = (known after apply) + } + + # digitalocean_vpc.example_vpc (example_vpc) will be created + + resource "digitalocean_vpc" "example_vpc" { + + created_at = (known after apply) + + default = (known after apply) + + id = (known after apply) + + ip_range = "10.10.10.0/24" +cdktf-demo + name = "pilot-test-tofu-vpc-1" + + region = "blr1" + + urn = (known after apply) + } + + Plan: 5 to add, 0 to change, 0 to destroy. + + Do you want to perform these actions? + OpenTofu will perform the actions described above. + Only 'yes' will be accepted to approve. +cdktf-demo Enter a value: yes +cdktf-demo digitalocean_vpc.example_vpc: Creating... +cdktf-demo digitalocean_volume.example_volume: Creating... +cdktf-demo digitalocean_vpc.example_vpc: Creation complete after 4s [id=a2efcafc-c36e-4dc6-b0a0-05168c64e035] +cdktf-demo digitalocean_droplet.example_droplet: Creating... +cdktf-demo digitalocean_volume.example_volume: Creation complete after 6s [id=6ca3afb6-4363-11ef-8e54-0a58ac14b334] +cdktf-demo digitalocean_droplet.example_droplet: Still creating... [10s elapsed] +cdktf-demo digitalocean_droplet.example_droplet: Still creating... [20s elapsed] +cdktf-demo digitalocean_droplet.example_droplet: Still creating... [30s elapsed] +cdktf-demo digitalocean_droplet.example_droplet: Creation complete after 33s [id=433003236] +cdktf-demo digitalocean_volume_attachment.example_volume_attachment: Creating... +cdktf-demo digitalocean_project.example_project: Creating... +cdktf-demo digitalocean_project.example_project: Creation complete after 4s [id=883b0f81-94e0-4d25-a414-8c4ba59dc2ad] +cdktf-demo digitalocean_volume_attachment.example_volume_attachment: Still creating... [10s elapsed] +cdktf-demo digitalocean_volume_attachment.example_volume_attachment: Creation complete after 13s [id=433003236-6ca3afb6-4363-11ef-8e54-0a58ac14b334-20240716110706136600000001] +cdktf-demo + Apply complete! Resources: 5 added, 0 changed, 0 destroyed. + +No outputs found. +``` + +## Destroy +```sh +$ cdktf destroy +``` +```sh +⠇ Synthesizing +cdktf-demo Initializing the backend... +cdktf-demo Initializing provider plugins... + - Reusing previous version of digitalocean/digitalocean from the dependency lock file +cdktf-demo - Using previously-installed digitalocean/digitalocean v2.39.2 + + OpenTofu has been successfully initialized! + + You may now begin working with OpenTofu. Try running "tofu plan" to see + any changes that are required for your infrastructure. All OpenTofu commands + should now work. + + If you ever set or change modules or backend configuration for OpenTofu, + rerun this command to reinitialize your working directory. If you forget, other + commands will detect it and remind you to do so if necessary. +cdktf-demo - Fetching digitalocean/digitalocean 2.39.2 for linux_amd64... +cdktf-demo - Retrieved digitalocean/digitalocean 2.39.2 for linux_amd64 (signed, key ID F82037E524B9C0E8) + - Obtained digitalocean/digitalocean checksums for linux_amd64; All checksums for this platform were already tracked in the lock file +cdktf-demo Success! OpenTofu has validated the lock file and found no need for changes. +cdktf-demo digitalocean_vpc.example_vpc: Refreshing state... [id=a2efcafc-c36e-4dc6-b0a0-05168c64e035] +cdktf-demo digitalocean_volume.example_volume: Refreshing state... [id=6ca3afb6-4363-11ef-8e54-0a58ac14b334] +cdktf-demo digitalocean_droplet.example_droplet: Refreshing state... [id=433003236] +cdktf-demo digitalocean_volume_attachment.example_volume_attachment: Refreshing state... [id=433003236-6ca3afb6-4363-11ef-8e54-0a58ac14b334-20240716110706136600000001] +cdktf-demo digitalocean_project.example_project: Refreshing state... [id=883b0f81-94e0-4d25-a414-8c4ba59dc2ad] +cdktf-demo OpenTofu used the selected providers to generate the following execution plan. + Resource actions are indicated with the following symbols: + - destroy + + OpenTofu will perform the following actions: +cdktf-demo # digitalocean_droplet.example_droplet (example_droplet) will be destroyed + - resource "digitalocean_droplet" "example_droplet" { + - backups = false -> null + - created_at = "2024-07-16T11:06:20Z" -> null + - disk = 25 -> null + - graceful_shutdown = false -> null + - id = "433003236" -> null + - image = "ubuntu-24-04-x64" -> null + - ipv4_address = "159.65.149.187" -> null + - ipv4_address_private = "10.10.10.2" -> null + - ipv6 = false -> null + - locked = false -> null + - memory = 1024 -> null + - monitoring = false -> null + - name = "pilot-test-tofu-droplet-1" -> null + - price_hourly = 0.00893 -> null + - price_monthly = 6 -> null + - private_networking = true -> null + - region = "blr1" -> null + - resize_disk = true -> null + - size = "s-1vcpu-1gb" -> null + - ssh_keys = [ + - "39020628", + ] -> null + - status = "active" -> null + - tags = [] -> null + - urn = "do:droplet:433003236" -> null + - vcpus = 1 -> null + - volume_ids = [ + - "6ca3afb6-4363-11ef-8e54-0a58ac14b334", + ] -> null + - vpc_uuid = "a2efcafc-c36e-4dc6-b0a0-05168c64e035" -> null + } + + # digitalocean_project.example_project (example_project) will be destroyed + - resource "digitalocean_project" "example_project" { + - created_at = "2024-07-16T11:06:53Z" -> null + - description = "Project for playing around with Tofu" -> null + - environment = "Development" -> null + - id = "883b0f81-94e0-4d25-a414-8c4ba59dc2ad" -> null + - is_default = false -> null + - name = "Pilot Tofu Playground" -> null + - owner_id = 127652 -> null + - owner_uuid = "abbd47f101f301c9f7ab4e63c06b1b359158527f" -> null + - purpose = "Web Application" -> null + - resources = [ + - "do:droplet:433003236", + ] -> null + - updated_at = "2024-07-16T11:06:53Z" -> null + } + + # digitalocean_volume.example_volume (example_volume) will be destroyed + - resource "digitalocean_volume" "example_volume" { + - description = "an example volume" -> null + - droplet_ids = [ + - 433003236, + ] -> null + - filesystem_type = "ext4" -> null + - id = "6ca3afb6-4363-11ef-8e54-0a58ac14b334" -> null + - initial_filesystem_type = "ext4" -> null + - name = "pilot-test-tofu-volume-1" -> null +cdktf-demo - region = "blr1" -> null + - size = 10 -> null + - tags = [] -> null + - urn = "do:volume:6ca3afb6-4363-11ef-8e54-0a58ac14b334" -> null + } + + # digitalocean_volume_attachment.example_volume_attachment (example_volume_attachment) will be destroyed + - resource "digitalocean_volume_attachment" "example_volume_attachment" { + - droplet_id = 433003236 -> null + - id = "433003236-6ca3afb6-4363-11ef-8e54-0a58ac14b334-20240716110706136600000001" -> null + - volume_id = "6ca3afb6-4363-11ef-8e54-0a58ac14b334" -> null + } + + # digitalocean_vpc.example_vpc (example_vpc) will be destroyed + - resource "digitalocean_vpc" "example_vpc" { + - created_at = "2024-07-16 11:06:17 +0000 UTC" -> null + - default = false -> null + - id = "a2efcafc-c36e-4dc6-b0a0-05168c64e035" -> null + - ip_range = "10.10.10.0/24" -> null + - name = "pilot-test-tofu-vpc-1" -> null + - region = "blr1" -> null + - urn = "do:vpc:a2efcafc-c36e-4dc6-b0a0-05168c64e035" -> null + } + + Plan: 0 to add, 0 to change, 5 to destroy. + + Do you really want to destroy all resources? + OpenTofu will destroy all your managed infrastructure, as shown above. + There is no undo. Only 'yes' will be accepted to confirm. +cdktf-demo Enter a value: yes +cdktf-demo digitalocean_volume_attachment.example_volume_attachment: Destroying... [id=433003236-6ca3afb6-4363-11ef-8e54-0a58ac14b334-20240716110706136600000001] +cdktf-demo digitalocean_project.example_project: Destroying... [id=883b0f81-94e0-4d25-a414-8c4ba59dc2ad] +cdktf-demo digitalocean_project.example_project: Destruction complete after 3s +cdktf-demo digitalocean_volume_attachment.example_volume_attachment: Still destroying... [id=433003236-6ca3afb6-4363-11ef-8e54-0a58ac14b334-20240716110706136600000001, 10s elapsed] +cdktf-demo digitalocean_volume_attachment.example_volume_attachment: Destruction complete after 13s +cdktf-demo digitalocean_volume.example_volume: Destroying... [id=6ca3afb6-4363-11ef-8e54-0a58ac14b334] + digitalocean_droplet.example_droplet: Destroying... [id=433003236] +cdktf-demo digitalocean_volume.example_volume: Destruction complete after 1s +cdktf-demo digitalocean_droplet.example_droplet: Still destroying... [id=433003236, 10s elapsed] +cdktf-demo digitalocean_droplet.example_droplet: Still destroying... [id=433003236, 20s elapsed] +cdktf-demo digitalocean_droplet.example_droplet: Destruction complete after 23s +cdktf-demo digitalocean_vpc.example_vpc: Destroying... [id=a2efcafc-c36e-4dc6-b0a0-05168c64e035] +cdktf-demo digitalocean_vpc.example_vpc: Destruction complete after 1s +cdktf-demo + Destroy complete! Resources: 5 destroyed. +``` + +## Done +Now you know everything I know about CDKTF + +We're still aren't very far from HCLs. + +We don't have to convert Documents to HCL. But the actual superpower will be to call `plan/deploy/destroy` from Python. + +We can probably get the equivalent of `cdktf deploy` with some hacks around TerraformCli and jsii +References: +- https://github.com/hashicorp/terraform-cdk/blob/40a1a39a4655720aec8f1bdb93dd9689f6747fa5/packages/%40cdktf/cli-core/src/lib/models/terraform.ts + +- https://github.com/hashicorp/terraform-cdk/issues/237#issuecomment-864523914 \ No newline at end of file diff --git a/pilot/provision/cdktf-demo/cdktf.json b/pilot/provision/cdktf-demo/cdktf.json new file mode 100644 index 0000000..19bcfd6 --- /dev/null +++ b/pilot/provision/cdktf-demo/cdktf.json @@ -0,0 +1,12 @@ +{ + "language": "python", + "app": "pipenv run python main.py", + "projectId": "f35e3169-c26d-49bb-beae-fbe6c840f492", + "sendCrashReports": "false", + "terraformProviders": [], + "terraformModules": [], + "codeMakerOutput": "imports", + "context": { + + } +} diff --git a/pilot/provision/cdktf-demo/help b/pilot/provision/cdktf-demo/help new file mode 100644 index 0000000..6d69db7 --- /dev/null +++ b/pilot/provision/cdktf-demo/help @@ -0,0 +1,42 @@ +======================================================================================================== + + Your cdktf Python project is ready! + + cat help Prints this message + + Compile: + pipenv run ./main.py Compile and run the python code. + + Synthesize: + cdktf synth [stack] Synthesize Terraform resources to cdktf.out/ + + Diff: + cdktf diff [stack] Perform a diff (terraform plan) for the given stack + + Deploy: + cdktf deploy [stack] Deploy the given stack + + Destroy: + cdktf destroy [stack] Destroy the given stack + + Learn more about using modules and providers https://cdk.tf/modules-and-providers + +Use Providers: + + You can add prebuilt providers (if available) or locally generated ones using the add command: + + cdktf provider add "aws@~>3.0" null kreuzwerker/docker + + You can find all prebuilt providers on PyPI: https://pypi.org/user/cdktf-team/ + You can also install these providers directly through pipenv: + + pipenv install cdktf-cdktf-provider-aws + pipenv install cdktf-cdktf-provider-google + pipenv install cdktf-cdktf-provider-azurerm + pipenv install cdktf-cdktf-provider-docker + pipenv install cdktf-cdktf-provider-github + pipenv install cdktf-cdktf-provider-null + + You can also build any module or provider locally. Learn more: https://cdk.tf/modules-and-providers + +======================================================================================================== \ No newline at end of file diff --git a/pilot/provision/cdktf-demo/main-test.py b/pilot/provision/cdktf-demo/main-test.py new file mode 100644 index 0000000..dd6ebe2 --- /dev/null +++ b/pilot/provision/cdktf-demo/main-test.py @@ -0,0 +1,25 @@ +import pytest +from cdktf import Testing + +# The tests below are example tests, you can find more information at +# https://cdk.tf/testing + + +class TestMain: + def test_my_app(self): + assert True + + # stack = TerraformStack(Testing.app(), "stack") + # app_abstraction = MyApplicationsAbstraction(stack, "app-abstraction") + # synthesized = Testing.synth(stack) + + # def test_should_contain_container(self): + # assert Testing.to_have_resource(self.synthesized, Container.TF_RESOURCE_TYPE) + + # def test_should_use_an_ubuntu_image(self): + # assert Testing.to_have_resource_with_properties(self.synthesized, Image.TF_RESOURCE_TYPE, { + # "name": "ubuntu:latest", + # }) + + # def test_check_validity(self): + # assert Testing.to_be_valid_terraform(Testing.full_synth(stack)) diff --git a/pilot/provision/cdktf-demo/main.py b/pilot/provision/cdktf-demo/main.py new file mode 100755 index 0000000..cb10cc5 --- /dev/null +++ b/pilot/provision/cdktf-demo/main.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +from cdktf import App, Fn, TerraformStack, TerraformVariable +from cdktf_cdktf_provider_digitalocean.droplet import Droplet +from cdktf_cdktf_provider_digitalocean.project import Project +from cdktf_cdktf_provider_digitalocean.provider import DigitaloceanProvider +from cdktf_cdktf_provider_digitalocean.volume import Volume +from cdktf_cdktf_provider_digitalocean.volume_attachment import VolumeAttachment +from cdktf_cdktf_provider_digitalocean.vpc import Vpc +from constructs import Construct + + +class MyStack(TerraformStack): + def __init__(self, scope: Construct, id: str): + super().__init__(scope, id) + + region = "blr1" + prefix = "pilot-test-tofu" + ip_range = "10.10.10.0/24" + image = "ubuntu-24-04-x64" + size = "s-1vcpu-1gb" + ssh_key_id = "39020628" # This has to be a str because ssh_keys is Sequence[str] + + do_token_variable = TerraformVariable( + self, + "do_token", + type="string", + ) + # variable "do_token" {} + + # variable.string_value to get the actual value of the variable + DigitaloceanProvider(self, "digitalocean", token=do_token_variable.string_value) + # provider "digitalocean" { + # token = var.do_token + # } + + vpc = Vpc(self, "example_vpc", name=f"{prefix}-vpc-1", region=region, ip_range=ip_range) + # resource "digitalocean_vpc" "example_vpc" { + # name = "pilot-test-tofu-vpc-1" + # region = "blr1" + # ip_range = "10.10.10.0/24" + # } + + droplet = Droplet( + self, + "example_droplet", + image=image, + name=f"{prefix}-droplet-1", + region=region, + size=size, + vpc_uuid=vpc.id, + ssh_keys=[ssh_key_id], + ) + # resource "digitalocean_droplet" "example_droplet" { + # image = "ubuntu-24-04-x64" + # name = "pilot-test-tofu-droplet-1" + # region = "blr1" + # size = "s-1vcpu-1gb" + # vpc_uuid = digitalocean_vpc.example_vpc.id + # ssh_keys = [39020628] + # } + + volume = Volume( + self, + "example_volume", + region=region, + name=f"{prefix}-volume-1", + size=10, + initial_filesystem_type="ext4", + description="an example volume", + ) + # resource "digitalocean_volume" "example_volume" { + # region = "blr1" + # name = "pilot-test-tofu-volume-1" + # size = 10 + # initial_filesystem_type = "ext4" + # description = "an example volume" + # } + + VolumeAttachment( + self, + "example_volume_attachment", + droplet_id=Fn.tonumber(droplet.id), + volume_id=volume.id, + ) + # resource "digitalocean_volume_attachment" "example_volume_attachment" { + # droplet_id = digitalocean_droplet.example_droplet.id + # volume_id = digitalocean_volume.example_volume.id + # } + + Project( + self, + "example_project", + name="Pilot Tofu Playground", + description="Project for playing around with Tofu", + purpose="Web Application", + environment="Development", + resources=[droplet.urn], + ) + # resource "digitalocean_project" "example_project" { + # name = "Pilot Tofu Playground" + # description = "Project for playing around with Tofu" + # purpose = "Web Application" + # environment = "Development" + # resources = [digitalocean_droplet.example_droplet.urn] + # } + + +app = App() +MyStack(app, "cdktf-demo") + +app.synth() diff --git a/pilot/provision/cdktf-demo/terraform.cdktf-demo.tfstate b/pilot/provision/cdktf-demo/terraform.cdktf-demo.tfstate new file mode 100644 index 0000000..be03bc2 --- /dev/null +++ b/pilot/provision/cdktf-demo/terraform.cdktf-demo.tfstate @@ -0,0 +1,9 @@ +{ + "version": 4, + "terraform_version": "1.7.3", + "serial": 9, + "lineage": "16df10de-c4e7-c42a-9aff-3cc0e79942f8", + "outputs": {}, + "resources": [], + "check_results": null +} diff --git a/pilot/provision/cdktf-demo/terraform.cdktf-demo.tfstate.backup b/pilot/provision/cdktf-demo/terraform.cdktf-demo.tfstate.backup new file mode 100644 index 0000000..01b9151 --- /dev/null +++ b/pilot/provision/cdktf-demo/terraform.cdktf-demo.tfstate.backup @@ -0,0 +1,168 @@ +{ + "version": 4, + "terraform_version": "1.7.3", + "serial": 7, + "lineage": "16df10de-c4e7-c42a-9aff-3cc0e79942f8", + "outputs": {}, + "resources": [ + { + "mode": "managed", + "type": "digitalocean_droplet", + "name": "example_droplet", + "provider": "provider[\"registry.opentofu.org/digitalocean/digitalocean\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "backups": false, + "created_at": "2024-07-16T11:06:20Z", + "disk": 25, + "droplet_agent": null, + "graceful_shutdown": false, + "id": "433003236", + "image": "ubuntu-24-04-x64", + "ipv4_address": "159.65.149.187", + "ipv4_address_private": "10.10.10.2", + "ipv6": false, + "ipv6_address": "", + "locked": false, + "memory": 1024, + "monitoring": false, + "name": "pilot-test-tofu-droplet-1", + "price_hourly": 0.00893, + "price_monthly": 6, + "private_networking": true, + "region": "blr1", + "resize_disk": true, + "size": "s-1vcpu-1gb", + "ssh_keys": [ + "39020628" + ], + "status": "active", + "tags": null, + "timeouts": null, + "urn": "do:droplet:433003236", + "user_data": null, + "vcpus": 1, + "volume_ids": [], + "vpc_uuid": "a2efcafc-c36e-4dc6-b0a0-05168c64e035" + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjozNjAwMDAwMDAwMDAwLCJkZWxldGUiOjYwMDAwMDAwMDAwLCJ1cGRhdGUiOjM2MDAwMDAwMDAwMDB9LCJzY2hlbWFfdmVyc2lvbiI6IjEifQ==", + "dependencies": [ + "digitalocean_vpc.example_vpc" + ] + } + ] + }, + { + "mode": "managed", + "type": "digitalocean_project", + "name": "example_project", + "provider": "provider[\"registry.opentofu.org/digitalocean/digitalocean\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "created_at": "2024-07-16T11:06:53Z", + "description": "Project for playing around with Tofu", + "environment": "Development", + "id": "883b0f81-94e0-4d25-a414-8c4ba59dc2ad", + "is_default": false, + "name": "Pilot Tofu Playground", + "owner_id": 127652, + "owner_uuid": "abbd47f101f301c9f7ab4e63c06b1b359158527f", + "purpose": "Web Application", + "resources": [ + "do:droplet:433003236" + ], + "timeouts": null, + "updated_at": "2024-07-16T11:06:53Z" + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiZGVsZXRlIjoxODAwMDAwMDAwMDB9fQ==", + "dependencies": [ + "digitalocean_droplet.example_droplet", + "digitalocean_vpc.example_vpc" + ] + } + ] + }, + { + "mode": "managed", + "type": "digitalocean_volume", + "name": "example_volume", + "provider": "provider[\"registry.opentofu.org/digitalocean/digitalocean\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "description": "an example volume", + "droplet_ids": [], + "filesystem_label": null, + "filesystem_type": "ext4", + "id": "6ca3afb6-4363-11ef-8e54-0a58ac14b334", + "initial_filesystem_label": null, + "initial_filesystem_type": "ext4", + "name": "pilot-test-tofu-volume-1", + "region": "blr1", + "size": 10, + "snapshot_id": null, + "tags": null, + "urn": "do:volume:6ca3afb6-4363-11ef-8e54-0a58ac14b334" + }, + "sensitive_attributes": [], + "private": "bnVsbA==" + } + ] + }, + { + "mode": "managed", + "type": "digitalocean_volume_attachment", + "name": "example_volume_attachment", + "provider": "provider[\"registry.opentofu.org/digitalocean/digitalocean\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "droplet_id": 433003236, + "id": "433003236-6ca3afb6-4363-11ef-8e54-0a58ac14b334-20240716110706136600000001", + "volume_id": "6ca3afb6-4363-11ef-8e54-0a58ac14b334" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "digitalocean_droplet.example_droplet", + "digitalocean_volume.example_volume", + "digitalocean_vpc.example_vpc" + ] + } + ] + }, + { + "mode": "managed", + "type": "digitalocean_vpc", + "name": "example_vpc", + "provider": "provider[\"registry.opentofu.org/digitalocean/digitalocean\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "created_at": "2024-07-16 11:06:17 +0000 UTC", + "default": false, + "description": "", + "id": "a2efcafc-c36e-4dc6-b0a0-05168c64e035", + "ip_range": "10.10.10.0/24", + "name": "pilot-test-tofu-vpc-1", + "region": "blr1", + "timeouts": null, + "urn": "do:vpc:a2efcafc-c36e-4dc6-b0a0-05168c64e035" + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiZGVsZXRlIjoxMjAwMDAwMDAwMDB9fQ==" + } + ] + } + ], + "check_results": null +}